@impact0815/node-red-contrib-home-connect 0.0.0-stage → 0.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/BUILD-INFO.json +23 -0
- package/CHANGELOG.md +52 -0
- package/LICENSE +21 -0
- package/NOTICE +19 -0
- package/README.de.md +326 -0
- package/README.md +325 -2
- package/SECURITY.md +47 -0
- package/docs/API-COVERAGE.md +59 -0
- package/docs/ARCHITECTURE.md +95 -0
- package/docs/DASHBOARD.de.md +121 -0
- package/docs/DASHBOARD.md +121 -0
- package/docs/FIRST-PUSH.md +42 -0
- package/docs/LOCAL-LAN.de.md +150 -0
- package/docs/LOCAL-LAN.md +150 -0
- package/docs/MESSAGE-API.md +111 -0
- package/docs/RELEASE.md +78 -0
- package/docs/TROUBLESHOOTING.de.md +230 -0
- package/docs/TROUBLESHOOTING.md +230 -0
- package/docs/images/README.md +10 -0
- package/docs/images/dashboard-details-en.png +0 -0
- package/docs/images/dashboard-overview-en.png +0 -0
- package/docs/official-api-contract.json +418 -0
- package/examples/01-first-steps-device-list.json +148 -0
- package/examples/02-events.json +165 -0
- package/examples/03-safe-read-write.json +155 -0
- package/examples/04-local-read-only.json +214 -0
- package/examples/dashboard-dishwasher-washer-oven.json +628 -0
- package/examples/dashboard-screenshot-simulated.json +405 -0
- package/examples/demo-home-connect-flowfuse-1.34.1-scriptless.json +390 -0
- package/lib/client.js +600 -0
- package/lib/constants.js +66 -0
- package/lib/dashboard-i18n.js +255 -0
- package/lib/device-label.js +39 -0
- package/lib/errors.js +51 -0
- package/lib/health.js +525 -0
- package/lib/local-client.js +1014 -0
- package/lib/local-crypto.js +122 -0
- package/lib/local-diagnostics.js +115 -0
- package/lib/local-profile.js +706 -0
- package/lib/local-trace.js +103 -0
- package/lib/oauth.js +23 -0
- package/lib/rate-limiter.js +186 -0
- package/lib/simulator.js +290 -0
- package/lib/sse.js +58 -0
- package/lib/validation.js +194 -0
- package/lib/websocket-transport.js +374 -0
- package/nodes/home-connect.html +795 -0
- package/nodes/home-connect.js +699 -0
- package/nodes/locales/de/home-connect.html +19 -0
- package/nodes/locales/de/home-connect.json +10 -0
- package/nodes/locales/en-US/home-connect.json +10 -0
- package/package.json +71 -4
package/README.md
CHANGED
|
@@ -1,3 +1,326 @@
|
|
|
1
|
-
#
|
|
1
|
+
# node-red-contrib-home-connect
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**English · [Deutsch](README.de.md)**
|
|
4
|
+
|
|
5
|
+
[](https://github.com/impact0815/node-red-contrib-home-connect/actions/workflows/ci.yml)
|
|
6
|
+
[](CHANGELOG.md)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
Node-RED nodes for Home Connect: direct, read-only LAN access to appliance profiles plus the existing official cloud API with OAuth, discovery, SSE, rate-limit protection, health/warnings, and guarded writes. The project conceptually follows the discovery-first and safe-write approach of [`impact0815/node-red-contrib-viessmann`](https://github.com/impact0815/node-red-contrib-viessmann), but is an independent Home Connect implementation.
|
|
10
|
+
|
|
11
|
+
> **Unofficial community project.** This package is not affiliated with, endorsed by, or supported by Home Connect GmbH, BSH Hausgeräte GmbH, Bosch, Siemens, Neff, Gaggenau, or any other brand. Use it at your own risk. Appliance control can create heat, motion, water use, and other hazards. Test with the simulator and dry-run first.
|
|
12
|
+
|
|
13
|
+
## Read this first
|
|
14
|
+
|
|
15
|
+
- **Client ID and Client Secret come from your own Application in the Home Connect Developer Portal**, not from the Home Connect mobile app.
|
|
16
|
+
- This build uses the **OAuth 2.0 Authorization Code Grant with a client secret and without PKCE**.
|
|
17
|
+
- The **Client Secret is confidential**. Never publish it in screenshots, forums, issues, flows, or Git repositories. If exposed, regenerate it in the Developer Portal and authorize again.
|
|
18
|
+
- The Redirect URI in the Developer Portal and Node-RED must match **character for character**.
|
|
19
|
+
- Always **save and deploy** a connection before reopening it and starting authorization.
|
|
20
|
+
- The experimental local protocol is undocumented and can change with firmware. Local access is **hard read-only**; profile PSK/IV values are secrets.
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- confidential OAuth 2.0 Authorization Code flow, CSRF state, and refresh-token rotation
|
|
25
|
+
- Client Secret and refresh token in the Node-RED credential store, not exported flows
|
|
26
|
+
- Production, China, official Home Connect simulator, and built-in offline simulator
|
|
27
|
+
- recursive discovery and grouping of Profile Downloader JSON/XML sets, with one central profile-to-Host/IP assignment in the configuration node
|
|
28
|
+
- direct local WebSocket reads/events over AES-CBC/HMAC or TLS-PSK; transport defaults to **Auto** from the profile and can be overridden centrally
|
|
29
|
+
- service-version-driven handshake/read sequencing, unsolicited appliance values, housekeeping responses, and complete session rebuilds
|
|
30
|
+
- optional sanitized in-memory or protected JSONL protocol trace with no PSK, IV, keys, nonces, or appliance/network identifiers
|
|
31
|
+
- selectors show `type — friendly name — brand/model — …ID suffix`; the complete technical ID remains unchanged internally
|
|
32
|
+
- strict local-only host validation, credential-backed profile JSON, and an unconditional `LOCAL_READ_ONLY` write barrier
|
|
33
|
+
- profile-based resolution of hexadecimal XML `uid`/`refUID` values and referenced enums into semantic Home Connect keys, followed by automatic status/setting/value/program classification
|
|
34
|
+
- Server-Sent Events (SSE) with automatic reconnect
|
|
35
|
+
- normalized health model: `ok`, `running`, `info`, `warning`, `action_required`, `offline`, `error`
|
|
36
|
+
- deduplicated warnings carrying German and English text from appliance status, event `level`/`handling`, connection, API, and OAuth; the Dashboard displays only the selected language
|
|
37
|
+
- separate data and structured-error outputs
|
|
38
|
+
- persistent, configurable 24-hour request budget shared by equal Client IDs, with an HTTP 429 circuit breaker
|
|
39
|
+
- guarded writes with global enable, appliance-type allowlist, confirmation token, dry-run, and live capability checks
|
|
40
|
+
- no automatic retries of write requests
|
|
41
|
+
- English and German README, help, troubleshooting, and examples
|
|
42
|
+
- Dashboard 2.0 example with saved DE/EN selection, localized UI/appliance/enum/program/option names, initial snapshots, partial-event merging, offline/reconnect, and cloud plus local read-only paths
|
|
43
|
+
- separate fully simulated, credential-free screenshot flow for reproducible GitHub/npm documentation images
|
|
44
|
+
- zero runtime dependencies; Node.js 18+ and Node-RED 3+
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
### Local TGZ file
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
cd ~/.node-red
|
|
52
|
+
npm install /absolute/path/node-red-contrib-home-connect-0.2.0.tgz
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Restart Node-RED completely and reload the browser with **Ctrl+F5**.
|
|
56
|
+
|
|
57
|
+
### Docker example
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
docker cp node-red-contrib-home-connect-0.2.0.tgz node-red:/tmp/
|
|
61
|
+
docker exec node-red npm install --prefix /data /tmp/node-red-contrib-home-connect-0.2.0.tgz
|
|
62
|
+
docker restart node-red
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Upgrade from 0.1.0
|
|
66
|
+
|
|
67
|
+
Replace the old package cleanly so Node-RED cannot load a stale copy:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
cd ~/.node-red
|
|
71
|
+
npm uninstall node-red-contrib-home-connect
|
|
72
|
+
rm -rf node_modules/node-red-contrib-home-connect
|
|
73
|
+
npm install --force /absolute/path/node-red-contrib-home-connect-0.2.0.tgz
|
|
74
|
+
node -p "require('./node_modules/node-red-contrib-home-connect/BUILD-INFO.json')"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Expect `hc-0.2.0-final` and `pkce: false`. Restart the container when applicable. Existing cloud configuration remains compatible; do not reuse incomplete or old authorization links/codes.
|
|
78
|
+
|
|
79
|
+
## Step-by-step setup for non-technical users
|
|
80
|
+
|
|
81
|
+
### A. Try it without an account
|
|
82
|
+
|
|
83
|
+
1. In Node-RED choose **Menu → Import → Examples → node-red-contrib-home-connect → 01-first-steps-device-list**.
|
|
84
|
+
2. Deploy.
|
|
85
|
+
3. Click the Inject button on the left.
|
|
86
|
+
4. The Debug sidebar shows three local test appliances.
|
|
87
|
+
5. The built-in simulator makes no external Home Connect connection and needs no credentials.
|
|
88
|
+
|
|
89
|
+
### B. Connect real appliances locally (read-only)
|
|
90
|
+
|
|
91
|
+
1. Use the community [Home Connect Profile Downloader](https://github.com/bruestel/homeconnect-profile-downloader) to export the appliance JSON/XML files.
|
|
92
|
+
2. Store the extracted directory on the Node-RED host with restrictive filesystem permissions. In Docker, mount it read-only, for example at `/data/homeconnect-profiles`. The path must be the path **inside the Node-RED container**, not a path on your laptop.
|
|
93
|
+
3. Create a Home Connect configuration and choose **Local LAN (read-only)**.
|
|
94
|
+
4. Enter the server-side profile directory and click **Scan profiles / Detect devices**. The recursive scanner groups each appliance JSON with its matching `DeviceDescription.xml` and `FeatureMapping.xml`. The result says, for example, **3 device profiles found**. Incomplete sets and duplicate profile IDs are listed separately and must be fixed in the folder.
|
|
95
|
+
5. A card appears for every complete device profile. Enter one Host/IP in each card. Missing, malformed, public, and non-local addresses are marked. Leave **Connection type** at **Auto (recommended)**; Auto honors the profile's declared AES/TLS/PSK transport first and uses IV presence only as a fallback.
|
|
96
|
+
6. Click **Test connection** in every device card. Even before Done/Deploy, it uses the visible Host/IP and transport and shows separate stages for IP reachability, profile, transport, WebSocket, session, services, and read-only data. Rejected protocol resources identify action, version, and device code while network failures remain a separate class. It never sends a write request.
|
|
97
|
+
7. Click **Done → Deploy**. The editor serializes `localDeviceMappings` on every card change and once more on Done, so the exact assignments persist after deploy; do not create mapping JSON yourself.
|
|
98
|
+
8. In a Read node select only the configured appliance and read resource. In an Events node select one configured appliance or **All configured appliances**. Neither node contains a Host/IP field.
|
|
99
|
+
9. Do not attach a Write node: local writes are always rejected with `LOCAL_READ_ONLY` before local network I/O.
|
|
100
|
+
|
|
101
|
+
Under **Advanced**, **Paste profile JSON manually (optional)** is a fallback. Use either the folder or manual JSON. When a folder is set, the manual editor is collapsed/disabled and ignored. A button can generate the optional credential JSON from the detected profiles and completed mappings; no placeholder, sample key, or hand-written mapping is required. The same section can temporarily enable the safe protocol trace: with no path it is a bounded test display; with an absolute path it is JSONL mode `0600` on POSIX, with sensitive fields removed. On Windows, restrict the path with an account-specific NTFS ACL because POSIX mode bits are not reliable there.
|
|
102
|
+
|
|
103
|
+
The runtime connects only to private/link-local targets at `ws://host:80/homeconnect` (AES/HMAC) or `wss://host:443/homeconnect` (TLS-PSK). PSK/IV are never emitted. Full setup, Docker, protocol boundary, and troubleshooting: **[Local LAN guide](docs/LOCAL-LAN.md)**.
|
|
104
|
+
|
|
105
|
+
Appliance selectors use concise labels such as `Dishwasher — Geschirrspüler — Siemens SX678X36TE — …4576`. The shortened suffix is display-only; flows and runtime calls continue to use the full unmodified technical ID.
|
|
106
|
+
|
|
107
|
+
### C. Create your own Developer Portal Application
|
|
108
|
+
|
|
109
|
+
1. Sign in to the [Home Connect Developer Portal](https://developer.home-connect.com/).
|
|
110
|
+
2. Create your **own Application**.
|
|
111
|
+
3. Select the **Authorization Code Grant Flow**.
|
|
112
|
+
4. Generate a Client Secret.
|
|
113
|
+
5. Keep **PKCE disabled**, because this package build sends no PKCE parameters.
|
|
114
|
+
6. Register the Redirect URI that Node-RED will use.
|
|
115
|
+
7. Store the Client ID and Client Secret securely.
|
|
116
|
+
|
|
117
|
+
These values do **not** come from the Home Connect mobile app.
|
|
118
|
+
|
|
119
|
+
### D. Choose the correct Redirect URI
|
|
120
|
+
|
|
121
|
+
Pattern:
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
https://<node-red-host-reachable-from-your-browser>:<port>/home-connect/oauth/callback
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Example using a deliberately fictional hostname:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
https://nodered.example.net/home-connect/oauth/callback
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The string must be identical in both places:
|
|
134
|
+
|
|
135
|
+
- same `http` or `https`
|
|
136
|
+
- same hostname
|
|
137
|
+
- same port
|
|
138
|
+
- path ends exactly with `/home-connect/oauth/callback`
|
|
139
|
+
- **no** trailing slash
|
|
140
|
+
|
|
141
|
+
**About localhost:** `localhost` always means the computer running the browser. Use it only when the browser and Node-RED run on the same computer. For Node-RED on a NAS, Raspberry Pi, server, or container, use a Node-RED hostname or IP address that the browser can reach.
|
|
142
|
+
|
|
143
|
+
### E. Create the cloud Node-RED connection
|
|
144
|
+
|
|
145
|
+
1. Add a Home Connect node to the workspace.
|
|
146
|
+
2. Create a new `home-connect-config` under **Connection**.
|
|
147
|
+
3. Use a clear name such as `Home Connect Production – Home`. Do not name a Production connection `Simulator`.
|
|
148
|
+
4. Select the environment.
|
|
149
|
+
5. Enter the Client ID, Client Secret, and exact Redirect URI.
|
|
150
|
+
6. Start with the smallest practical scopes.
|
|
151
|
+
7. Initially keep the local budget at **900 API calls per 24 hours** and the minimum interval at **250 ms**.
|
|
152
|
+
8. Leave **Allow write access** off initially.
|
|
153
|
+
9. Click **Done**.
|
|
154
|
+
10. **Deploy**.
|
|
155
|
+
11. Reopen the connection. Only now is **Authorize** enabled.
|
|
156
|
+
12. Click **Authorize**, sign in to Home Connect, and grant access.
|
|
157
|
+
13. Authorization has finished when the browser displays **Home Connect authorized**.
|
|
158
|
+
14. Close that window and click **Test** in Node-RED. Appliances then appear automatically in the appliance selectors.
|
|
159
|
+
|
|
160
|
+
## Scopes in plain language
|
|
161
|
+
|
|
162
|
+
`IdentifyAppliance` is required for the appliance list. Add appliance-specific permissions when possible.
|
|
163
|
+
|
|
164
|
+
| Purpose | Example |
|
|
165
|
+
|---|---|
|
|
166
|
+
| Discover appliances only | `IdentifyAppliance` |
|
|
167
|
+
| Monitor dishwasher, washer, and oven | `IdentifyAppliance Dishwasher-Monitor Washer-Monitor Oven-Monitor` |
|
|
168
|
+
| Read and control the example dashboard | `IdentifyAppliance Dishwasher-Monitor Dishwasher-Control Dishwasher-Settings Washer-Monitor Washer-Control Washer-Settings Oven-Monitor Oven-Control Oven-Settings` |
|
|
169
|
+
|
|
170
|
+
The generic `Monitor` scope is not sufficient for every Application/account. After changing scopes, authorize again so a new refresh token receives the changed permissions.
|
|
171
|
+
|
|
172
|
+
## Normalized health and warning model
|
|
173
|
+
|
|
174
|
+
Every Discover, Read, Events, Write, and error output contains `msg.health`, `msg.warnings`, and the same information under `msg.homeConnect`. Snapshots and discovery entries additionally carry `payload.health`, `payload.warnings`, `payload.healthSchema`, and `payload.healthAt`. Dashboard flows therefore do not need to interpret Home Connect enums themselves.
|
|
175
|
+
|
|
176
|
+
```js
|
|
177
|
+
msg.health = 'action_required';
|
|
178
|
+
msg.warnings = [{
|
|
179
|
+
source: 'status',
|
|
180
|
+
code: 'HC_OPERATION_ACTION_REQUIRED',
|
|
181
|
+
severity: 'critical',
|
|
182
|
+
text: {
|
|
183
|
+
de: 'Das Gerät benötigt eine Aktion vor Ort.',
|
|
184
|
+
en: 'The appliance requires an action on site.'
|
|
185
|
+
},
|
|
186
|
+
transient: false
|
|
187
|
+
}];
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The model covers `OperationState`, `DoorState`, `RemoteControlActive`, `RemoteControlStartAllowed`, `LocalControlActive`, appliance/SSE connectivity, event `level` and `handling`, OAuth state, API errors, and rate limits. Short-lived notices such as `Finished`, ordinary appliance events, and `CONNECTED` are deduplicated and expire automatically. `DISCONNECTED`/offline remains until a connection or snapshot signal confirms recovery. Raw values are preserved so future enum values are not lost.
|
|
191
|
+
|
|
192
|
+
## Included nodes
|
|
193
|
+
|
|
194
|
+
| Node | Purpose |
|
|
195
|
+
|---|---|
|
|
196
|
+
| **Home Connect API** | shared local read-only or cloud OAuth configuration, scopes, and cloud write enable |
|
|
197
|
+
| **Home Connect discover** | dynamically load the user's appliances and capabilities |
|
|
198
|
+
| **Home Connect read** | read status, settings, programs, options, images, and supported map resources |
|
|
199
|
+
| **Home Connect events** | receive local WebSocket or cloud SSE events for all appliances or one appliance |
|
|
200
|
+
| **Home Connect write** | send cloud programs, settings, and commands through safety checks; local is always rejected |
|
|
201
|
+
|
|
202
|
+
Every functional node has two outputs: **data/result/event** and **structured error**.
|
|
203
|
+
|
|
204
|
+
## Example flows
|
|
205
|
+
|
|
206
|
+
Find these under **Import → Examples → node-red-contrib-home-connect**:
|
|
207
|
+
|
|
208
|
+
| File | Content |
|
|
209
|
+
|---|---|
|
|
210
|
+
| `01-first-steps-device-list.json` | simplest start: built-in simulator and appliance list |
|
|
211
|
+
| `02-events.json` | one all-appliance event stream, filtering, and Debug output |
|
|
212
|
+
| `03-safe-read-write.json` | read a snapshot and validate a write as dry-run only |
|
|
213
|
+
| `04-local-read-only.json` | anonymized local Discover/Read/Events flow with no Write node |
|
|
214
|
+
| `dashboard-dishwasher-washer-oven.json` | Dashboard 2.0: automatic/saved DE/EN display, initial snapshot plus local/cloud event merging, retained last-known state, offline/reconnect handling, compact overview, and detail cards |
|
|
215
|
+
| `dashboard-screenshot-simulated.json` | credential-free deterministic screenshot demo with three clearly simulated appliances; requires only Node-RED Dashboard 2 |
|
|
216
|
+
| `demo-home-connect-flowfuse-1.34.1-scriptless.json` | isolated, scriptless-template Demo flow supplied for FlowFuse Dashboard 1.34.1; deterministic, credential-free, and network-free |
|
|
217
|
+
|
|
218
|
+
The dashboard also requires `@flowfuse/node-red-dashboard`:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
cd ~/.node-red
|
|
222
|
+
npm install @flowfuse/node-red-dashboard
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The examples start with the built-in simulator. For real appliances, either use a local read-only connection or authorize a Production cloud connection, load the appliance list, and replace the connection in the Home Connect nodes. The shared reducer accepts complete snapshots and partial `STATUS`/`NOTIFY` events without clearing fields that were not part of the update. Offline events retain the last known values, and reconnect events resume live updates. Local controls are disabled by `readOnly`; cloud write nodes must stay in dry-run first. Technical keys remain unchanged internally; localization affects display only. See the [Dashboard guide](docs/DASHBOARD.md) for language selection and screenshot-flow instructions.
|
|
226
|
+
|
|
227
|
+
## Documentation screenshots
|
|
228
|
+
|
|
229
|
+
The release documentation uses only the isolated simulated Demo and includes two reviewed captures:
|
|
230
|
+
|
|
231
|
+

|
|
232
|
+
|
|
233
|
+

|
|
234
|
+
|
|
235
|
+
Both reviewed images use the English UI and show only `SIMULATED` Demo data. `npm run release:check` refuses publication if either file is missing, structurally invalid, or differs from the reviewed user-provided PNG. The completed visual review found no browser profiles, hostnames, addresses, account names, real appliance identifiers, tokens, QR codes, profiles, or unrelated tabs/windows.
|
|
236
|
+
|
|
237
|
+
## Appliance information and firmware — an important boundary
|
|
238
|
+
|
|
239
|
+
The publicly documented Home Connect API exposes appliance information such as name, brand, appliance type, `vib`/E-number, and connection state when supplied by the appliance/account. Discovery and the Dashboard display these values where available.
|
|
240
|
+
|
|
241
|
+
**Firmware version, firmware history, and firmware update are not provided by the publicly documented API.** This package does not pretend to implement firmware features, does not call undocumented firmware endpoints, and does not attempt to trigger updates. Check firmware and updates only through official manufacturer/Home Connect channels.
|
|
242
|
+
|
|
243
|
+
## Troubleshooting / FAQ
|
|
244
|
+
|
|
245
|
+
### `CONFIG_NOT_FOUND` when authorization starts
|
|
246
|
+
|
|
247
|
+
The button or an imported flow refers to a configuration node that is not present in the running Node-RED runtime. A simulator/example configuration may have been referenced, or the new configuration was not deployed.
|
|
248
|
+
|
|
249
|
+
**Fix:** select the correct connection → **Done** → **Deploy** → reopen the connection → start a new authorization. Do not continue in an old browser tab.
|
|
250
|
+
|
|
251
|
+
### Connection name and environment do not match
|
|
252
|
+
|
|
253
|
+
A name such as `Simulator` with the Production environment is technically possible but easy to misuse. The editor now warns about this. Rename it clearly and deploy again.
|
|
254
|
+
|
|
255
|
+
### The browser shows `ERR_EMPTY_RESPONSE` or connection failed on localhost after sign-in
|
|
256
|
+
|
|
257
|
+
Home Connect redirected the browser to `localhost`, but Node-RED runs on another computer. Change the Redirect URI in both the Developer Portal and Node-RED to a Node-RED host reachable from the browser, match it exactly, deploy, and start OAuth again.
|
|
258
|
+
|
|
259
|
+
### `unauthorized_client` / `client or redirection URI not authorized`
|
|
260
|
+
|
|
261
|
+
Usually the Redirect URI does not match exactly. Check protocol, host, port, path, and trailing slash. Also confirm that PKCE is disabled for the Developer Portal Application. This build sends no PKCE parameters.
|
|
262
|
+
|
|
263
|
+
### Old code still runs after a package update
|
|
264
|
+
|
|
265
|
+
Node-RED loads runtime code only at startup. Uninstall the old package, install the new TGZ with `--force`, restart Node-RED or its container completely, and hard-reload the browser. Verify the build information. Then restart OAuth completely; old authorization URLs and one-time codes are invalid.
|
|
266
|
+
|
|
267
|
+
### `No refresh token is stored. Complete OAuth authorization first.`
|
|
268
|
+
|
|
269
|
+
OAuth did not complete. Start authorization again and wait for **Home Connect authorized**. Only then use Test, Discover, Read, or Events.
|
|
270
|
+
|
|
271
|
+
### `insufficient_scope`
|
|
272
|
+
|
|
273
|
+
The stored token lacks the required permission. Enter `IdentifyAppliance` plus suitable appliance-specific scopes, save, deploy, and authorize again. Merely editing the scope text does not update an existing token.
|
|
274
|
+
|
|
275
|
+
### Events node remains on `reconnecting`
|
|
276
|
+
|
|
277
|
+
Authorization or monitor/event scopes are usually missing. First confirm that **Test** or the appliance-list example can load appliances. Inspect the Events node's error output, correct scopes, and authorize again. Prefer one all-appliance stream because the API limits concurrent streams.
|
|
278
|
+
|
|
279
|
+
### `health`, `warnings`, and rate limits
|
|
280
|
+
|
|
281
|
+
`health` is the summarized state; `warnings` provides stable codes and German/English text. By default, the configuration node permits **900 API attempts in every rolling 24-hour window**, leaving 100 calls in reserve below the vendor limit of 1000. The configurable range is 1–1000; equal Client IDs use the strictest active configuration inside one Node-RED process. REST requests, retries, and SSE connection attempts each count separately. State is persisted below the Node-RED `userDir` in `.home-connect`, so deploys and restarts do not reset the budget.
|
|
282
|
+
|
|
283
|
+
When the local budget is exhausted, a structured `LOCAL_RATE_LIMITED` error with `retryAfter` and `resetAt` is returned **before network access**. If Home Connect returns HTTP 429, a remaining period embedded in the error text, such as `75502 seconds`, is also recognized and persisted as a circuit breaker; this package sends no further Home Connect API requests during that period. A 429 response is not retried automatically. Other hosts or applications that use the same Home Connect Application cannot be coordinated, so do not raise the reserve to 1000 without a reason and use one config node per Client ID.
|
|
284
|
+
|
|
285
|
+
For `HC_API_RATE_LIMITED`, reduce polling and observe `retryAfter`. For `HC_OAUTH_INSUFFICIENT_SCOPE` or `HC_OAUTH_AUTHORIZATION_EXPIRED`, correct scopes or authorization and then authorize again. The example Dashboard disables start actions while offline, in error, requiring action, or blocked from remote control.
|
|
286
|
+
|
|
287
|
+
### How do I know authorization worked?
|
|
288
|
+
|
|
289
|
+
The callback page displays **Home Connect authorized**. **Test** then reports an appliance count, and **Load appliances** populates the selectors automatically.
|
|
290
|
+
|
|
291
|
+
See [Troubleshooting (EN)](docs/TROUBLESHOOTING.md) for the complete decision tree.
|
|
292
|
+
|
|
293
|
+
## Security
|
|
294
|
+
|
|
295
|
+
- Set a strong `credentialSecret` in `settings.js` before storing credentials.
|
|
296
|
+
- Protect the editor, Dashboard, and callback with HTTPS, authentication, and network controls.
|
|
297
|
+
- Never publish Client Secrets, tokens, real hostnames, appliance IDs, or OAuth codes in issues or screenshots.
|
|
298
|
+
- If a secret is exposed, regenerate it in the Developer Portal and authorize again immediately.
|
|
299
|
+
- Request minimum scopes.
|
|
300
|
+
- Keep `allowWrite` off by default; test every new write with dry-run.
|
|
301
|
+
- Use a deployment-specific confirmation token and appliance-type allowlist for write nodes.
|
|
302
|
+
- Follow manufacturer safety instructions and Home Connect terms.
|
|
303
|
+
|
|
304
|
+
More details: [SECURITY.md](SECURITY.md).
|
|
305
|
+
|
|
306
|
+
## Development and validation
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
npm run validate
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Validation covers syntax, JSON/flow files, unit and simulator integration tests, and `npm pack --dry-run`. GitHub Actions tests Node.js 18, 20, and 22.
|
|
313
|
+
|
|
314
|
+
## More documentation
|
|
315
|
+
|
|
316
|
+
- [Troubleshooting (EN)](docs/TROUBLESHOOTING.md)
|
|
317
|
+
- [Architecture](docs/ARCHITECTURE.md)
|
|
318
|
+
- [Message API](docs/MESSAGE-API.md)
|
|
319
|
+
- [API coverage](docs/API-COVERAGE.md)
|
|
320
|
+
- [Dashboard](docs/DASHBOARD.md)
|
|
321
|
+
- [Contributing](CONTRIBUTING.md)
|
|
322
|
+
- [Changelog](CHANGELOG.md)
|
|
323
|
+
|
|
324
|
+
## License
|
|
325
|
+
|
|
326
|
+
MIT. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Local appliance profiles
|
|
4
|
+
|
|
5
|
+
Local profile PSKs and IVs are equivalent to device credentials. Prefer a server-side profile directory readable only by the Node-RED service account, or use the optional credential-backed manual profile JSON field under **Advanced** with a strong `credentialSecret` in `settings.js`. The configuration node stores the non-secret profile-to-Host/IP assignment once; exported flows can therefore expose private addresses even though they never contain folder-based PSK/IV values. Sanitize both before sharing. Never export profiles in flows, logs, screenshots, support bundles, or bug reports.
|
|
6
|
+
|
|
7
|
+
The local transport rejects public network targets and is hard read-only. Do not weaken these controls. If a profile is exposed, remove the copy, obtain a fresh profile where the appliance/account supports it, and review LAN access.
|
|
8
|
+
|
|
9
|
+
The optional local protocol trace is disabled by default. It records decrypted protocol messages only after recursive redaction and never records PSK, IV, derived keys, ciphertext, OAuth data, authentication nonces, appliance IDs, serial numbers, MAC addresses, SSIDs, or IP fields. On POSIX, a configured JSONL trace file is created and enforced with mode `0600`; Windows does not expose equivalent POSIX mode bits reliably, so protect the trace path with an account-restricted NTFS ACL. Without a path, entries remain in a bounded memory buffer. Treat even sanitized traces as private operational data, inspect them before sharing, and disable/delete them after diagnosis.
|
|
10
|
+
|
|
11
|
+
## Supported version
|
|
12
|
+
|
|
13
|
+
During the 0.x development phase, security fixes are applied to the latest published release.
|
|
14
|
+
|
|
15
|
+
## Deployment checklist
|
|
16
|
+
|
|
17
|
+
- Set a strong `credentialSecret` in Node-RED settings before entering OAuth credentials.
|
|
18
|
+
- Serve the editor, Dashboard and OAuth callback over HTTPS.
|
|
19
|
+
- Protect the editor and Dashboard with authentication and network controls.
|
|
20
|
+
- Expose only the callback path needed by Home Connect; do not expose the Node-RED editor anonymously.
|
|
21
|
+
- Request the minimum appliance-specific scopes.
|
|
22
|
+
- Keep `allowWrite` off unless a flow needs it.
|
|
23
|
+
- Keep every new write node in dry-run until its exact request has been inspected.
|
|
24
|
+
- Use a unique confirmation token and an appliance-type allowlist.
|
|
25
|
+
- Never place client secret, refresh token, confirmation token or access token in a Function node, flow, Git repository or debug output.
|
|
26
|
+
- Never place local profile PSK/IV values or profile archives in a Function node, flow, Git repository or debug output.
|
|
27
|
+
- Keep local protocol tracing disabled except during diagnosis; inspect sanitized JSONL before sharing and delete it afterward.
|
|
28
|
+
- Never publish a real redirect URI, hostname, appliance ID, serial number, authorization code or OAuth state in screenshots or issues.
|
|
29
|
+
- If a client secret is exposed, regenerate it in the Home Connect Developer Portal, replace it in Node-RED and complete a new authorization.
|
|
30
|
+
- Review Home Connect Developer Program terms and appliance manufacturer safety instructions.
|
|
31
|
+
|
|
32
|
+
## Design properties
|
|
33
|
+
|
|
34
|
+
- OAuth state is random, memory-only, single-use and expires after ten minutes. This confidential-client flow deliberately sends no PKCE parameters.
|
|
35
|
+
- Client secrets, refresh tokens and per-writer confirmation tokens use Node-RED credentials; they are not exported with a flow.
|
|
36
|
+
- No arbitrary URL/method writer exists.
|
|
37
|
+
- Write payloads are checked against refreshed device capabilities, data types, `readWrite` access, ranges and allowed values.
|
|
38
|
+
- Program starts check remote-control/start/local-control/operation status.
|
|
39
|
+
- Write requests are not automatically retried.
|
|
40
|
+
- Normal API requests have a configurable timeout. A persisted sliding-window limiter counts REST and SSE connection attempts before network access; the default is 900 per 24 hours. HTTP 429 opens a local circuit breaker for the reported remaining period instead of being retried.
|
|
41
|
+
- OAuth success/error pages disable caching and set restrictive browser headers.
|
|
42
|
+
- Built-in simulator performs no external I/O.
|
|
43
|
+
- Local transports accept only private/link-local targets and expose only read resources; local writes are rejected before network I/O.
|
|
44
|
+
|
|
45
|
+
## Reporting a vulnerability
|
|
46
|
+
|
|
47
|
+
Do not open a public issue containing credentials, private infrastructure data or exploit details. Contact the package maintainer privately and include the affected version, impact, sanitized reproduction and suggested remediation. Revoke affected Home Connect credentials immediately in the Developer Program, deploy the replacement secret and restart Node-RED after rotating secrets.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Official API contract and coverage
|
|
2
|
+
|
|
3
|
+
The cloud client in version 0.2.0 remains checked against the two official Swagger 2.0 files supplied for the 0.1.0 revision:
|
|
4
|
+
|
|
5
|
+
| Specification | SHA-256 | Host | Operations |
|
|
6
|
+
| --- | --- | --- | ---: |
|
|
7
|
+
| `hcsdk-simulation.yaml` | `5942f5ca450a46fa9a6f53ff6d13627972040f105dcd786efddcf9a44ce376a3` | `simulator.home-connect.com` | 28 |
|
|
8
|
+
| `hcsdk-production.yaml` | `a0704118d429eb1a7becf9d624068a2c48ce8d7c0a2250128be2487ff0758c57` | `api.home-connect.com` | 46 |
|
|
9
|
+
|
|
10
|
+
The generated, machine-readable inventory is `official-api-contract.json`. The original YAML files are not redistributed in the npm package.
|
|
11
|
+
|
|
12
|
+
## Contract decisions
|
|
13
|
+
|
|
14
|
+
- API paths use the documented `/api` base path.
|
|
15
|
+
- JSON reads and writes use `application/vnd.bsh.sdk.v1+json`.
|
|
16
|
+
- OAuth uses the documented `accessCode` flow and the `/security/oauth/authorize` and `/security/oauth/token` endpoints on the selected environment host. The private-application implementation uses a client secret and deliberately omits PKCE parameters.
|
|
17
|
+
- Request bodies retain the documented `{ "data": ... }` envelope.
|
|
18
|
+
- JPEG image reads return `{ contentType, data }`, where `data` is a Node.js `Buffer`.
|
|
19
|
+
- Production-only command and cleaning-robot map resources are not queried during generic official-simulator discovery.
|
|
20
|
+
- HTTP 204 write responses become an empty object.
|
|
21
|
+
|
|
22
|
+
## Read coverage
|
|
23
|
+
|
|
24
|
+
The read node exposes a finite operation list rather than accepting arbitrary URLs:
|
|
25
|
+
|
|
26
|
+
- appliances and one appliance
|
|
27
|
+
- complete and single status values
|
|
28
|
+
- complete and single settings
|
|
29
|
+
- all, available, active and selected programs
|
|
30
|
+
- complete and single active/selected program options
|
|
31
|
+
- production command discovery
|
|
32
|
+
- image metadata and JPEG image data
|
|
33
|
+
- all production cleaning-robot map GET resources: maps, occupancy grid, layout, cleaning status, detected objects, rooms, zones, robot position, restrictions and cleaning summaries
|
|
34
|
+
- capability discovery and combined snapshots
|
|
35
|
+
|
|
36
|
+
The appliance object is passed through, including documented fields such as name, brand, type, `vib` and connected state when returned by the API.
|
|
37
|
+
|
|
38
|
+
## Firmware is outside the public contract
|
|
39
|
+
|
|
40
|
+
Neither the checked public production/simulation contracts nor the documented operation set provides firmware version, firmware history, or firmware update. Version 0.2.0 therefore exposes no firmware operation, does not synthesize firmware data, and does not call undocumented firmware endpoints. Its separate experimental local transport is read-only and limited to the documented-in-project `/ro/*` inventory in [LOCAL-LAN.md](LOCAL-LAN.md).
|
|
41
|
+
|
|
42
|
+
Map operations use `msg.key` for the map ID or cleaning-summary counter. Operations for one detected object, room or zone additionally use `msg.subKey`.
|
|
43
|
+
|
|
44
|
+
## Write coverage and intentional restrictions
|
|
45
|
+
|
|
46
|
+
The writer supports the documented singular endpoints for:
|
|
47
|
+
|
|
48
|
+
- start and stop program
|
|
49
|
+
- select program
|
|
50
|
+
- set one setting
|
|
51
|
+
- execute one command
|
|
52
|
+
- set one option of the active program
|
|
53
|
+
- set one option of the selected program
|
|
54
|
+
|
|
55
|
+
Bulk setting, command and option writes are intentionally not exposed. Singular writes permit tighter per-value validation and avoid partial-success ambiguity. Arbitrary HTTP methods, paths and body envelopes are intentionally unsupported.
|
|
56
|
+
|
|
57
|
+
## Simulator differences
|
|
58
|
+
|
|
59
|
+
The supplied simulation contract does not define command or map endpoints, while the production contract does. The client records this difference explicitly: command discovery is skipped for the official simulator, and map operations remain production-only. The built-in offline simulator implements the common high-level interface and returns structured `404` errors for image/map content it does not model.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Components
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
Node-RED editor/runtime
|
|
7
|
+
├─ Home Connect API configuration
|
|
8
|
+
│ ├─ OAuth state (confidential client, no PKCE)
|
|
9
|
+
│ ├─ access-token memory cache
|
|
10
|
+
│ ├─ refresh token in Node-RED credentials
|
|
11
|
+
│ ├─ shared API/simulator client
|
|
12
|
+
│ └─ per-appliance HealthMonitor
|
|
13
|
+
├─ discover ── capability cache (5 minutes)
|
|
14
|
+
├─ read ────── finite operation router
|
|
15
|
+
├─ events ──── SSE parser + Last-Event-ID reconnect loop
|
|
16
|
+
└─ write ───── security gates + live validation
|
|
17
|
+
|
|
18
|
+
Client abstraction
|
|
19
|
+
├─ HomeConnectClient (production, China, official simulator)
|
|
20
|
+
├─ LocalHomeConnectClient (LAN profiles, hard read-only)
|
|
21
|
+
│ └─ LocalApplianceSession
|
|
22
|
+
│ ├─ RFC 6455 transport (private/link-local targets only)
|
|
23
|
+
│ ├─ AES-CBC + chained HMAC or TLS 1.2 PSK
|
|
24
|
+
│ ├─ negotiated /ei, /ci, /iz, /ni and /ro versions
|
|
25
|
+
│ ├─ sanitized optional protocol trace
|
|
26
|
+
│ └─ /ro/* values + full-session reconnect/heartbeat
|
|
27
|
+
└─ BuiltinSimulator (offline, deterministic, event-capable)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## OAuth lifecycle
|
|
31
|
+
|
|
32
|
+
1. An authenticated Node-RED editor user starts authorization through an admin route.
|
|
33
|
+
2. A random, short-lived `state` is generated in memory. No PKCE parameters are created or sent.
|
|
34
|
+
3. The browser is redirected to the selected Home Connect authorization endpoint.
|
|
35
|
+
4. The public callback validates state and its ten-minute lifetime.
|
|
36
|
+
5. The authorization code is exchanged for tokens. `client_id`, `client_secret`, the unchanged `redirect_uri` and the code are form-encoded only in the token request.
|
|
37
|
+
6. The refresh token is saved with `RED.nodes.addCredentials`; the access token remains in memory. Client ID and client secret are never added to the browser authorization URL beyond the required client ID.
|
|
38
|
+
7. Access tokens refresh before use when expired and once after an HTTP 401.
|
|
39
|
+
|
|
40
|
+
No password grant, automated login or credential scraping is used.
|
|
41
|
+
|
|
42
|
+
## Local LAN lifecycle and read-only boundary
|
|
43
|
+
|
|
44
|
+
The local profile scanner recursively loads Profile Downloader appliance JSON and groups matching DeviceDescription/FeatureMapping XML files by base name within the same directory. It returns only non-secret profile metadata to the editor. The configuration node owns the single `profileId` → Host/IP/connection assignment; Read and Events nodes store only a profile/appliance ID. Legacy encrypted profile JSON remains in the Node-RED credential store. PSK and IV never enter messages, diagnostics, logs, examples, or exported flows.
|
|
45
|
+
|
|
46
|
+
Before a socket is opened, DNS must resolve exclusively to private RFC1918, IPv4 link-local, IPv6 unique-local, or IPv6 link-local addresses. `Auto` first honors an explicit profile declaration of AES, TLS, or PSK and uses IV presence only as a fallback; a per-profile override is possible only in the central mapping. The editor posts the current card value to the test route and re-serializes all mappings on Done, so testing before deploy and runtime after deploy use the same Host/IP/transport assignment. The transport performs a direct RFC 6455 upgrade on the exact `/homeconnect` path with websocket-client-compatible `Host`, URL-derived `Origin`, `Upgrade`, `Connection`, key, and version headers; it sends no subprotocol, cookie, or authorization header. AES profiles use port 80 and persistent AES-256-CBC/HMAC state. TLS profiles use port 443 with TLS 1.2 PSK and a profile identity or `HCCOM_Local_App`. The first AES integrity/padding/decode error closes the connection; reconnect creates fresh cipher and HMAC chains. The editor test exposes seven deterministic stages and stops on the first root cause, so a transport/handshake failure cannot be followed by a synthetic values-unavailable error.
|
|
47
|
+
|
|
48
|
+
The appliance sends `/ei/initialValues`; the session responds with the same session/message IDs and the EI-version-specific application structure, then starts its own message counter at the advertised `edMsgID`. It requests `/ci/services` at version 1 **without a `data` member**, parses flat or nested service lists, negotiates legacy `/ci/authentication` (`POST` first, documented `GET` fallback) when `ci < 3`, and announces `/ei/deviceReady` at the negotiated EI version, also without `data`. Optional identity/network reads select `/iz/info` versus `/ci/info` and `/ni/info` from the service inventory. It then sends only `GET`, using the advertised `ro` version, in this order: `/ro/allMandatoryValues`, `/ro/values`, `/ro/allDescriptionChanges`, `/ro/activeProgram`, and `/ro/selectedProgram`.
|
|
49
|
+
|
|
50
|
+
Incoming unsolicited `NOTIFY`/`RESPONSE` messages are applied before matching pending requests. Successful or device-pushed initial/mandatory/value payloads count as read-only evidence, so one unsupported fallback resource does not invalidate data already delivered by the appliance. Device-originated housekeeping `GET`/`POST` messages receive `RESPONSE` with the same appliance `msgID` and do not advance the client counter. Non-zero/non-200 response codes retain resource, action, version, and device code; if every read path is rejected, all attempts are returned in sanitized diagnostics.
|
|
51
|
+
|
|
52
|
+
The optional local protocol trace records decrypted, sanitized protocol envelopes and lifecycle events in a bounded memory buffer and, when an absolute path is configured, JSONL mode `0600` on POSIX. Windows must protect the path with an account-restricted NTFS ACL because it does not report equivalent POSIX mode bits reliably. Recursive redaction removes PSK/IV/key/authentication/OAuth material, nonces, and device/network identifiers. It never records ciphertext or transport headers. Trace I/O failure cannot weaken the read-only boundary or crash the session.
|
|
53
|
+
|
|
54
|
+
Read-only is enforced at three levels: the local client has no write route, its `write()` always throws `LOCAL_READ_ONLY`, and the Write node rejects a local configuration before cloud capability validation or network I/O. `allowWrite` is forced false for local configurations.
|
|
55
|
+
|
|
56
|
+
## Discovery model
|
|
57
|
+
|
|
58
|
+
Discovery starts with `/api/homeappliances`. For each appliance it reads status, settings, available/active/selected programs and, where the supplied contract defines it, commands. Every available program is then opened individually so its actual options and constraints are captured. Unsupported endpoints and failed program details become resource-labelled `discoveryErrors`; they do not erase the rest of the snapshot. Successful discovery is cached for five minutes and invalidated after every write.
|
|
59
|
+
|
|
60
|
+
## Write threat model and gates
|
|
61
|
+
|
|
62
|
+
A request must pass all applicable gates:
|
|
63
|
+
|
|
64
|
+
1. **Configuration gate** – `allowWrite` is enabled.
|
|
65
|
+
2. **Node action gate** – only seven named actions can reach the client; no arbitrary HTTP path or method is accepted.
|
|
66
|
+
3. **Confirmation gate** – optional exact token on each message; the configured token is a Node-RED credential.
|
|
67
|
+
4. **Type gate** – optional appliance-type allowlist.
|
|
68
|
+
5. **Fresh capability gate** – programs, options, settings and commands are reloaded.
|
|
69
|
+
6. **Constraint gate** – value type, access (`readWrite`), allowed values, min, max, step size and duplicate options.
|
|
70
|
+
7. **Operational gate** – connected, remote control active, remote start allowed, local control inactive and ready state for program starts.
|
|
71
|
+
8. **Retry gate** – writes are sent once and never retried automatically.
|
|
72
|
+
|
|
73
|
+
Dry-run performs gates 1–7 without sending the request. If dry-run is selected in the editor, an input message cannot turn it off.
|
|
74
|
+
|
|
75
|
+
## SSE lifecycle
|
|
76
|
+
|
|
77
|
+
The event node opens an all-appliance or per-appliance stream. The parser supports comments/keep-alive, event, data, id and retry fields and arbitrary chunk boundaries. The latest event ID is sent as `Last-Event-ID` after reconnect. The client emits synthetic `CONNECTED`/`DISCONNECTED` lifecycle events and promotes an all-appliance event's `data.haId` to the normalized event envelope. Network/API errors go to output 2. The node reconnects from one to thirty seconds and aborts immediately when removed, redeployed or when the shared configuration closes.
|
|
78
|
+
|
|
79
|
+
For local configurations, the same node subscribes to per-appliance WebSocket sessions instead. Sessions emit `CONNECTED`, `DISCONNECTED`, and normalized `STATUS`; ping/pong runs every 20 seconds. Reconnect uses jittered exponential backoff from about one to at most 60 seconds and rebuilds the transport, crypto state, session ID, message counter, services, authentication, device-ready notification, optional info reads, and read-only snapshot.
|
|
80
|
+
|
|
81
|
+
## Health normalization
|
|
82
|
+
|
|
83
|
+
One `HealthMonitor` belongs to each configuration node, so Discover, Read, Events and Write nodes sharing that connection also share current appliance state. It maps known operation, door, remote/local-control and connection signals to seven stable health values. Event `level`/`handling`, API/OAuth errors and rate limits become bilingual warning records. Current status conditions replace previous conditions; transient event/Finished/Connected notices are deduplicated and time-bounded. Error-output assessments are not retained, preventing one failed request from poisoning later successful output. Unknown enum values remain in the raw payload and produce at most one informational warning.
|
|
84
|
+
|
|
85
|
+
## Transport controls
|
|
86
|
+
|
|
87
|
+
Cloud JSON requests use the vendor media type from the supplied Swagger contracts. API reads have a configurable timeout and bounded retries for network errors and temporary 5xx responses. Writes and HTTP 429 responses are never automatically retried. Binary image reads return a `Buffer`; SSE intentionally uses a long-lived connection instead of the normal request timeout.
|
|
88
|
+
|
|
89
|
+
Every REST attempt and SSE connection attempt first acquires a permit from a persisted sliding-window limiter. The default is 900 permits per rolling 24 hours and a 250 ms minimum spacing; both are configurable within safety bounds, and config nodes with the same environment and Client ID share the strictest active settings. The state file below the Node-RED `userDir` contains only timestamps and a blocked-until value. When the local budget is exhausted, the request fails locally. A vendor HTTP 429 opens a persistent circuit breaker using `Retry-After` or a remaining-seconds value extracted from the API error description; if neither exists, the limiter conservatively blocks for one configured window.
|
|
90
|
+
|
|
91
|
+
Direct LAN sessions do not consume the cloud limiter. Their controls are private-address validation, request/handshake timeouts, WebSocket heartbeat, bounded reconnect, strict message parsing, per-direction serialized cipher state, and fail-closed integrity handling.
|
|
92
|
+
|
|
93
|
+
## Simulator
|
|
94
|
+
|
|
95
|
+
The built-in simulator implements the same high-level client interface. It includes a dishwasher, washer and oven, validates the same constraints, changes active program state, emits SSE-like events, counts down time and simulates oven temperature. It performs no external I/O.
|