homebridge-pax-calima 2.5.0-beta.2 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -89
- package/README.md +81 -47
- package/RELEASE_NOTES.md +18 -26
- package/config.schema.json +11 -10
- package/docs/BETA1-LIVE-DIAGNOSTIC.md +119 -0
- package/docs/STABLE-PROMOTION.md +38 -0
- package/docs/VALIDATION.md +21 -47
- package/docs/VERIFICATION.md +39 -33
- package/docs/pi-live-control-evidence-20261025.jsonl +42 -0
- package/lib/accessory.js +12 -7
- package/package.json +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,91 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
- Point the plugin website and support links to the new [SvaraHome site](https://homebridge.svarahome.kernowekconsulting.co.uk).
|
|
18
|
-
- Confirm live Boost, Pause and cancellation on both fans, plus capped slider control on Wetroom. All 48 automated tests pass across Node 22/24 and Homebridge 1/2 for the control implementation.
|
|
19
|
-
|
|
20
|
-
## 2.5.0-beta.1 — Boost and Pause
|
|
21
|
-
|
|
22
|
-
### SvaraHome
|
|
23
|
-
|
|
24
|
-
- Introduced the SvaraHome name across the plugin listing, setup guidance and release copy.
|
|
25
|
-
- Added the approved layered house-and-fan logo and prepared a Homebridge icon.
|
|
26
|
-
- Retained the existing package identifier and fan accessory identities for upgrade continuity.
|
|
27
|
-
|
|
28
|
-
### Everyday controls
|
|
29
|
-
|
|
30
|
-
- Added timed Boost and Pause switches, shown by default with individual visibility settings.
|
|
31
|
-
- Added early return to automatic ventilation and readback after control commands.
|
|
32
|
-
- Used the fan’s native timer so temporary actions can finish while Homebridge is disconnected.
|
|
33
|
-
- Changed the speed slider to temporary manual control, preserving persistent speed presets.
|
|
34
|
-
- Made Boost and Pause mutually exclusive and prevented an inactive switch-off from cancelling the other action.
|
|
35
|
-
- Restricted manual controls to operating mode 00 without changing installation settings.
|
|
36
|
-
|
|
37
|
-
### Bluetooth and telemetry
|
|
38
|
-
|
|
39
|
-
- Added explicit address/PIN routing and validation for six- and eight-digit PINs.
|
|
40
|
-
- Required confirmed authentication and stopped unattended retries after a rejected PIN.
|
|
41
|
-
- Queued Bluetooth sessions across fans and added bounded operations, connection cleanup and late-connection recovery handling.
|
|
42
|
-
- Reported communication failures for unconfirmed commands, stale telemetry and invalid readings.
|
|
43
|
-
- Reconciled the fan’s current override through polling and after restart.
|
|
44
|
-
|
|
45
|
-
### Setup and upgrades
|
|
46
|
-
|
|
47
|
-
- Replaced the non-actionable Boost event service.
|
|
48
|
-
- Removed unsupported temperature, humidity and light services.
|
|
49
|
-
- Applied changed quiet-hours schedules once, preserving later official-app edits.
|
|
50
|
-
- Updated configuration guidance and supported Node versions.
|
|
51
|
-
- Added 32 automated tests covering protocol handling, native Homebridge services, configuration, queues, recorded telemetry and the maintained Bluetooth library’s real classes.
|
|
52
|
-
|
|
53
|
-
### Dependency security
|
|
54
|
-
|
|
55
|
-
- Replaced the old Bluetooth dependency with the maintained Noble fork, removing the vulnerable archive and native-build dependency chain.
|
|
56
|
-
- Confirmed zero reported vulnerabilities in fresh full and production audits, including a separately resolved Linux ARM64 production tree.
|
|
57
|
-
- Added high/critical audit gates and a native-module load check to CI.
|
|
58
|
-
|
|
59
|
-
### Beta validation
|
|
60
|
-
|
|
61
|
-
- Automated tests passed across Node 22/24 and Homebridge 1/2.
|
|
62
|
-
- Verified isolated native Linux ARM64 installation/loading on the Pi under Node 22/24, without initialising Bluetooth or changing the running bridge.
|
|
63
|
-
- Live plugin deployment and older-fan authentication remain outstanding.
|
|
64
|
-
- Homebridge verification remains pending.
|
|
65
|
-
|
|
66
|
-
## 2.4.5
|
|
67
|
-
|
|
68
|
-
- Replaced the removed Silent Hours service lookup with `getServiceById` for Homebridge 2 compatibility.
|
|
69
|
-
- Reported live validation on Homebridge 2.4.0 and Node 24.19.0.
|
|
70
|
-
|
|
71
|
-
## 2.4.4
|
|
72
|
-
|
|
73
|
-
- Improved Silent Hours time-field hints and invalid-time warnings.
|
|
74
|
-
|
|
75
|
-
## 2.4.3
|
|
76
|
-
|
|
77
|
-
- Added schedule configuration, an optional Silent Hours switch and optional light sensor exposure.
|
|
78
|
-
- Added plugin display metadata and reorganised settings.
|
|
79
|
-
- Wrote Silent Hours during every poll. This behaviour is replaced in 2.5.0.
|
|
80
|
-
|
|
81
|
-
## 2.4.2
|
|
82
|
-
|
|
83
|
-
- Disabled the optional humidity tile by default and rewrote setup guidance.
|
|
84
|
-
|
|
85
|
-
## 2.4.1 / 2.4.0
|
|
86
|
-
|
|
87
|
-
- Revised Bluetooth connection handling and polling.
|
|
88
|
-
|
|
89
|
-
## Earlier releases
|
|
90
|
-
|
|
91
|
-
- Added initial Bluetooth integration, Homebridge lifecycle changes and fan services. Earlier sensor interpretations are corrected in 2.5.0.
|
|
3
|
+
## 2.5.0
|
|
4
|
+
|
|
5
|
+
- Introduced **SvaraHome**, with a new name and house-and-fan identity.
|
|
6
|
+
- Added a working **Boost Fan** switch for timed extra ventilation and early cancellation.
|
|
7
|
+
- Made **Fan Off** a timed pause and **Fan On** a return to automatic ventilation from either Pause or Boost. Added **Pause Fan** as an optional separate control.
|
|
8
|
+
- Added fan-managed timers so temporary actions can end while Homebridge is disconnected.
|
|
9
|
+
- Changed the speed slider to control a temporary session, preserving saved ventilation speed presets. Added an optional requested-speed limit for each fan.
|
|
10
|
+
- Updated controls to show confirmed state and measured speed, with communication faults for failed commands or stale/invalid readings.
|
|
11
|
+
- Added retries for temporary Bluetooth failures and retention of the newest waiting request across child-bridge restarts. A newer command replaces it; rejected authentication and incompatible responses stop retries.
|
|
12
|
+
- Required each fan’s address and its own six- or eight-digit PIN, with authentication confirmed before controls.
|
|
13
|
+
- Changed quiet-hours handling to save changed schedules once and preserve later edits made in the official app.
|
|
14
|
+
- Removed unsupported temperature, humidity and light tiles, and replaced the old event-only Boost service. Preserved fan accessory identities and room assignments.
|
|
15
|
+
- Added support for Node 22/24 with Homebridge 1/2.
|
|
16
|
+
- Added setup guidance through the [SvaraHome website](https://homebridge.svarahome.kernowekconsulting.co.uk).
|
package/README.md
CHANGED
|
@@ -1,81 +1,115 @@
|
|
|
1
1
|
# SvaraHome for Homebridge
|
|
2
2
|
|
|
3
|
+
<img src="assets/svarahome.png" alt="SvaraHome’s blue house and fan logo" width="160">
|
|
4
|
+
|
|
3
5
|
Give the fan a boost. Pause it for a quiet moment. Let it return to normal when the time is up.
|
|
4
6
|
|
|
5
|
-
SvaraHome brings local Bluetooth control for Pax Calima and Vent-Axia Svara fans
|
|
7
|
+
SvaraHome brings local Bluetooth control for Pax Calima and Vent-Axia Svara fans into Apple Home through your Homebridge host. No SvaraHome cloud account is needed.
|
|
6
8
|
|
|
7
|
-
[
|
|
9
|
+
[Website and support](https://homebridge.svarahome.kernowekconsulting.co.uk) · [Plugin on npm](https://www.npmjs.com/package/homebridge-pax-calima) · [Release notes](RELEASE_NOTES.md)
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
**SvaraHome 2.5.0** brings timed Boost, Pause and confirmed fan feedback to Apple Home.
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
## What you get in Apple Home
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
| Control | What it does |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Fan** | Shows measured speed as a percentage. Off starts a timed pause; On returns either Pause or Boost to automatic ventilation. |
|
|
18
|
+
| **Boost Fan** | Runs the fan at your chosen speed for a limited time. Turn it off to return sooner. Shown by default. |
|
|
19
|
+
| **Pause Fan** | Optional separate pause switch for status and automations. Hidden by default unless explicitly enabled. |
|
|
20
|
+
| **Silent Hours** | Optional switch for the fan’s saved quiet-hours schedule. It does not start an immediate pause. |
|
|
14
21
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{ "name": "Kitchen Fan", "mac": "58:2b:db:12:34:56", "pin": "00123456" }
|
|
21
|
-
],
|
|
22
|
-
"boostMinutes": 10,
|
|
23
|
-
"boostRpm": 2000,
|
|
24
|
-
"pauseMinutes": 10
|
|
25
|
-
}
|
|
26
|
-
```
|
|
22
|
+
**Fan Off is a timed pause, not a permanent shutdown.** The default is 10 minutes; choose the duration in Plugin Config. The fan’s own timer resumes automatic ventilation even if Homebridge disconnects. Apple Home’s Off label does not show that timer.
|
|
23
|
+
|
|
24
|
+
Boost and Pause share one temporary override. Starting either replaces the other. Turning the main Fan on returns to automatic ventilation; automatic operation can still leave the motor idle under the fan’s own rules.
|
|
25
|
+
|
|
26
|
+
The displayed speed comes from measured RPM. It can differ from the requested percentage while the motor settles. The speed slider starts a temporary session using the Boost duration; it leaves persistent ventilation speed presets in place. A zero-speed request starts the timed pause. Low nonzero requests use the supported minimum of 1000 RPM.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Temperature, humidity and light are **not exposed as ambient sensors**. SvaraHome does not provide a shower-detection sensor or infer room conditions from fan speed.
|
|
29
29
|
|
|
30
|
-
##
|
|
30
|
+
## Use your own words
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Assign each fan to its room in Apple Home. In a room named Kitchen, try:
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
- “Siri, turn on Boost Fan in the kitchen.”
|
|
35
|
+
- “Siri, turn off the kitchen fan.”
|
|
36
|
+
- “Siri, turn on the kitchen fan.”
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
Siri recognition depends on your actual accessory names and room assignments. Apple Home may retain a customised tile name; rename an existing control there if needed. You can also include the controls in your own scenes and automations.
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
Apple Home may show the controls together or as separate tiles, depending on its presentation settings. Homebridge’s Accessories page can also show child-bridge accessories when UI accessory control is available; check its bridge filter.
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
## Get started
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
You need Homebridge 1.8 or later within version 1, or Homebridge 2; Node 22.12 or later within Node 22, or Node 24; and a working Bluetooth adapter with the normal Bluetooth access for your Homebridge installation.
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
1. Install or update `homebridge-pax-calima` through Homebridge UI.
|
|
47
|
+
2. Open Plugin Config. Add each fan’s Bluetooth address and its own six- or eight-digit PIN from the official app. Keep leading zeroes. There is no default PIN or automatic pairing with nearby fans.
|
|
48
|
+
3. Choose the Boost speed/duration and Pause duration. Close the official app while Homebridge connects.
|
|
49
|
+
4. Save and use **Restart Child Bridge** on SvaraHome’s plugin card. A dedicated child bridge is recommended; pair it with Apple Home if it is not already paired.
|
|
50
|
+
5. Assign each fan to its room in Apple Home and check its controls.
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
Temporary controls require a supported fan operating mode. SvaraHome does not change the fan’s installation mode. A factory reset or accessory-cache reset is not part of normal setup or upgrading.
|
|
53
|
+
|
|
54
|
+
If you manage plugins from a terminal, install `homebridge-pax-calima@latest`. Prefer Homebridge UI when it manages your installation.
|
|
55
|
+
|
|
56
|
+
## Configuration
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"platform": "PaxCalima",
|
|
61
|
+
"name": "SvaraHome",
|
|
62
|
+
"fans": [
|
|
63
|
+
{
|
|
64
|
+
"name": "Kitchen Fan",
|
|
65
|
+
"mac": "58:2b:db:12:34:56",
|
|
66
|
+
"pin": "00123456"
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"boostMinutes": 10,
|
|
70
|
+
"boostRpm": 2000,
|
|
71
|
+
"pauseMinutes": 10,
|
|
72
|
+
"showBoostSwitch": true,
|
|
73
|
+
"showPauseSwitch": false
|
|
74
|
+
}
|
|
75
|
+
```
|
|
47
76
|
|
|
48
|
-
|
|
77
|
+
The address and PIN are examples. Use your own fan’s details. A Bluetooth address prefix alone does not establish compatibility. Empty or unusable configuration does not start Bluetooth discovery.
|
|
49
78
|
|
|
50
|
-
|
|
79
|
+
| Setting | Purpose |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `fans[].name` | Name for a newly added fan. Existing accessory identities and Home room assignments are retained. |
|
|
82
|
+
| `fans[].mac` / `fans[].pin` | Required address and PIN for that particular fan. |
|
|
83
|
+
| `boostMinutes` / `boostRpm` | Temporary Boost duration and requested speed. Defaults: 10 minutes and 2000 RPM. |
|
|
84
|
+
| `pauseMinutes` | Timed pause duration, including when the main Fan is turned off. Default: 10 minutes. |
|
|
85
|
+
| `showBoostSwitch` | Show Boost Fan. Default: `true`. |
|
|
86
|
+
| `showPauseSwitch` | Show the separate Pause Fan switch. Default: `false`; an explicitly enabled setting stays enabled. |
|
|
87
|
+
| `fans[].maxManualRpm` | Optional per-fan limit for Boost and slider requests. Leave blank for the 2500 RPM target limit, or use a lower speed confirmed to work on your fan. This does not cap displayed measurement or alter permanent presets. |
|
|
88
|
+
| `silentHoursStart` / `silentHoursEnd` | Optional saved quiet-hours schedule, in 24-hour format. Set both times, or leave both blank to retain the fan’s own schedule. |
|
|
89
|
+
| `showSilentSwitch` | Show the saved schedule’s enable/disable switch. Default: `false`. |
|
|
51
90
|
|
|
52
|
-
|
|
91
|
+
Boost and Pause durations accept 1–60 minutes. Boost speeds and per-fan target limits accept 1000–2500 RPM in steps of 25. Fans can differ in which targets they accept.
|
|
53
92
|
|
|
54
|
-
|
|
93
|
+
Changing quiet-hours times saves and checks the schedule once. Routine polling respects later schedule changes made in the official app. The Silent Hours switch enables or disables that saved schedule; use Fan Off for an immediate timed pause. Quiet-hours behaviour still depends on the fan’s firmware and settings.
|
|
55
94
|
|
|
56
|
-
|
|
57
|
-
- The old event-only Boost button is replaced by an actionable switch. Check scenes that referred to the old service. Pause is added by default.
|
|
58
|
-
- Temperature, humidity and light tiles are removed. The previous humidity/light values came from a heat-setting characteristic; the previous temperature conversion remains unverified. These values should not drive automations. Old `showHumidity` and `showLight` settings are ignored.
|
|
59
|
-
- Speed control now uses temporary manual override, leaving humidity, light and trickle speed presets alone.
|
|
60
|
-
- Quiet hours are no longer rewritten on every poll. The switch represents the native schedule's enabled flag.
|
|
61
|
-
- No factory reset or accessory-cache reset is required.
|
|
95
|
+
Hiding an optional switch removes its service. Check scenes and automations that use it before changing visibility; hiding it does not cancel a running override.
|
|
62
96
|
|
|
63
|
-
##
|
|
97
|
+
## If a fan is unavailable
|
|
64
98
|
|
|
65
|
-
|
|
99
|
+
Check its address and PIN privately in Plugin Config, Bluetooth range/adapter access, and whether the official app is still connected. Start with the Homebridge log’s fan-specific message; do not reset the accessory cache or power-cycle the Pi as a routine first step.
|
|
66
100
|
|
|
67
|
-
|
|
101
|
+
Temporary connection failures leave the newest manual request waiting for retry. A waiting request can start later when the fan reconnects. Turn the main Fan on to replace it with return-to-automatic. Siri may time out before recovery; that timeout does not cancel the waiting request.
|
|
68
102
|
|
|
69
|
-
|
|
103
|
+
Tiles follow confirmed fan state. Background readings are retained only within a 45-second freshness limit; failed commands, stale data and invalid readings report communication faults. A rejected PIN stops unattended authentication retries: correct the saved details, restart the child bridge, then try again.
|
|
70
104
|
|
|
71
|
-
|
|
105
|
+
## Upgrading to 2.5
|
|
72
106
|
|
|
73
|
-
|
|
107
|
+
Keep the existing fan accessory and its room assignment. Check each fan’s address/PIN and any scenes that used the previous Boost event service. Boost is now an actionable **Boost Fan** switch; **Pause Fan** is optional. Unsupported temperature, humidity and light services are removed, and the speed slider now controls a temporary session.
|
|
74
108
|
|
|
75
|
-
|
|
109
|
+
An explicitly enabled Pause switch remains enabled after upgrading. Turn off **Show Pause Fan in Apple Home** if you prefer only Fan and Boost Fan. No re-pairing is normally required.
|
|
76
110
|
|
|
77
|
-
|
|
111
|
+
## About the project
|
|
78
112
|
|
|
79
|
-
|
|
113
|
+
SvaraHome is independent of Apple, Homebridge, Pax and Vent-Axia. **Homebridge verification has not yet been granted.** Homebridge controls the verification badge and central plugin icon; bundling the SvaraHome artwork does not grant either.
|
|
80
114
|
|
|
81
|
-
|
|
115
|
+
For help, start with the [SvaraHome website](https://homebridge.svarahome.kernowekconsulting.co.uk) or [GitHub issues](https://github.com/KernowekConsulting/homebridge-pax-calima/issues). [Validation evidence](docs/VALIDATION.md) and [verification preparation](docs/VERIFICATION.md) are available separately.
|
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,41 +1,33 @@
|
|
|
1
|
-
# SvaraHome 2.5.0
|
|
1
|
+
# SvaraHome 2.5.0 — Your fan, at home
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A boost when you need it. A quiet moment when you want one. An easy way back to normal.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Meet **SvaraHome**: a new name, a new look and more useful everyday control of your Pax Calima or Vent-Axia Svara fan in Apple Home.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Familiar controls
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**Fan** is your everyday control. Turn it off for a timed pause; turn it on to return to automatic ventilation, whether the fan was paused or boosted.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
**Boost Fan** gives ventilation a temporary lift at your chosen speed and duration. The fan’s own timer returns it to automatic operation, even if Homebridge disconnects. Turn Boost Fan off to return sooner.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Try “Siri, turn on Boost Fan in the kitchen”, using the names and rooms in your Home. A separate **Pause Fan** switch is optional for status and automations.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
The speed slider now starts a temporary session, leaving your saved ventilation speed presets in place. Each fan can have its own requested-speed limit.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## Clearer feedback, less maintenance
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Controls reflect the fan’s confirmed state and measured speed. Failed commands or stale readings show a communication fault, so an unconfirmed request is not presented as success.
|
|
20
20
|
|
|
21
|
-
Bluetooth
|
|
21
|
+
Temporary Bluetooth interruptions no longer mean repeating your request: SvaraHome retries and keeps your latest instruction, including across child-bridge restarts. Siri may time out before recovery; a waiting request can still run when the fan reconnects.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
The optional **Maximum requested speed** setting caps Boost and slider targets separately for each fan. Measured speed remains unchanged.
|
|
26
|
-
|
|
27
|
-
Our older Wetroom fan accepted 2400 RPM but returned a zero-RPM override for a 2450 RPM request. Its tested limit is now 2400 RPM; Kitchen retains 2450 RPM. This is evidence from these fans, rather than a universal limit for every firmware version.
|
|
23
|
+
Quiet-hours schedules are saved when you change their times. Later schedule changes in the official app are respected.
|
|
28
24
|
|
|
29
25
|
## Before you upgrade
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
## Tested, with more to learn
|
|
38
|
-
|
|
39
|
-
Live checks confirmed Boost, Pause and cancellation on both fans, plus the capped speed slider on Wetroom. The control implementation passed 48 automated tests in each Node 22/24 and Homebridge 1/2 combination. Short successful trials do not establish uninterrupted Bluetooth reliability, and Siri voice recognition still depends on your Home names and scenes.
|
|
27
|
+
- Give every fan its own Bluetooth address and correct six- or eight-digit PIN in Plugin Config. Close the official app while Homebridge connects.
|
|
28
|
+
- Boost and Pause use the durations in SvaraHome’s Plugin Config, both 10 minutes by default. They do not inherit the countdown selected in the official app. Fan Off is temporary: automatic ventilation resumes when the Pause timer ends.
|
|
29
|
+
- Existing fan identities and room assignments are retained. Check scenes that used the old Boost event service, which is replaced by the working Boost Fan switch.
|
|
30
|
+
- Temperature, humidity and light tiles are removed because they were not verified ambient measurements.
|
|
31
|
+
- Use Node 22.12 or later within Node 22, or Node 24, with Homebridge 1.8+ or 2. After saving configuration, use Restart Child Bridge on SvaraHome’s plugin card.
|
|
40
32
|
|
|
41
|
-
|
|
33
|
+
Setup guidance and support are at the [SvaraHome website](https://homebridge.svarahome.kernowekconsulting.co.uk).
|
package/config.schema.json
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"title": "Fan PIN",
|
|
33
33
|
"type": "string",
|
|
34
34
|
"pattern": "^(?:[0-9]{6}|[0-9]{8})$",
|
|
35
|
-
"description": "Enter this fan
|
|
35
|
+
"description": "Enter this fan\u2019s six- or eight-digit PIN, including any leading zeroes. The PIN is stored in your Homebridge configuration.",
|
|
36
36
|
"secret": true
|
|
37
37
|
},
|
|
38
38
|
"maxManualRpm": {
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"showBoostSwitch": {
|
|
55
|
-
"title": "Show Boost in Apple Home",
|
|
55
|
+
"title": "Show Boost Fan in Apple Home",
|
|
56
56
|
"type": "boolean",
|
|
57
57
|
"default": true,
|
|
58
|
-
"description": "Start a timed boost.
|
|
58
|
+
"description": "Start a timed boost. Turn Boost Fan off, or turn the main Fan on, to return to automatic ventilation."
|
|
59
59
|
},
|
|
60
60
|
"boostMinutes": {
|
|
61
61
|
"title": "Boost duration (minutes)",
|
|
@@ -74,17 +74,18 @@
|
|
|
74
74
|
"description": "Choose a speed in steps of 25 RPM. The Home speed slider also starts a temporary session."
|
|
75
75
|
},
|
|
76
76
|
"showPauseSwitch": {
|
|
77
|
-
"title": "Show Pause in Apple Home",
|
|
77
|
+
"title": "Show Pause Fan in Apple Home",
|
|
78
78
|
"type": "boolean",
|
|
79
|
-
"default":
|
|
80
|
-
"description": "
|
|
79
|
+
"default": false,
|
|
80
|
+
"description": "Optional separate pause switch. The main Fan already pauses temporarily when turned off. Turn Fan on to return to automatic ventilation. Existing explicitly enabled Pause switches remain enabled."
|
|
81
81
|
},
|
|
82
82
|
"pauseMinutes": {
|
|
83
83
|
"title": "Pause duration (minutes)",
|
|
84
84
|
"type": "integer",
|
|
85
85
|
"minimum": 1,
|
|
86
86
|
"maximum": 60,
|
|
87
|
-
"default": 10
|
|
87
|
+
"default": 10,
|
|
88
|
+
"description": "Turning the main Fan off starts this timed pause, even when Pause Fan is hidden. The fan resumes automatically when its own timer ends."
|
|
88
89
|
},
|
|
89
90
|
"silentHoursStart": {
|
|
90
91
|
"title": "Quiet hours start",
|
|
@@ -96,13 +97,13 @@
|
|
|
96
97
|
"title": "Quiet hours end",
|
|
97
98
|
"type": "string",
|
|
98
99
|
"placeholder": "06:00",
|
|
99
|
-
"description": "Use 24-hour time, such as 06:00. Leave both fields blank to retain the fan
|
|
100
|
+
"description": "Use 24-hour time, such as 06:00. Leave both fields blank to retain the fan\u2019s existing schedule."
|
|
100
101
|
},
|
|
101
102
|
"showSilentSwitch": {
|
|
102
103
|
"title": "Show Silent Hours in Apple Home",
|
|
103
104
|
"type": "boolean",
|
|
104
105
|
"default": false,
|
|
105
|
-
"description": "Enable or disable the fan
|
|
106
|
+
"description": "Enable or disable the fan\u2019s saved quiet-hours schedule. This preserves its times; it does not start an immediate pause."
|
|
106
107
|
}
|
|
107
108
|
},
|
|
108
109
|
"required": [
|
|
@@ -128,7 +129,7 @@
|
|
|
128
129
|
},
|
|
129
130
|
{
|
|
130
131
|
"type": "section",
|
|
131
|
-
"title": "
|
|
132
|
+
"title": "Fan controls",
|
|
132
133
|
"items": [
|
|
133
134
|
"showBoostSwitch",
|
|
134
135
|
"boostMinutes",
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# beta.1 live diagnostic — 25 October 2026
|
|
2
|
+
|
|
3
|
+
Evidence collected through the existing authenticated Homebridge terminal. The initial examination (approximately 09:29–09:32 local time) was read-only. Subsequent sections explicitly record the owner's authorised configuration corrections, local validation updates, child-bridge restarts and reversible manual-control trials. No whole-Pi reboot or factory reset was performed.
|
|
4
|
+
|
|
5
|
+
## KEY SUMMARY
|
|
6
|
+
|
|
7
|
+
- The local validation hotfix is running on the Pi; npm remains the originally published `2.5.0-beta.1`. Source revision `9f30bae` passed 48 tests in each of four Node/Homebridge combinations.
|
|
8
|
+
- Wetroom's missing address was recovered from its unique cached identity. The owner corrected its PIN privately. Both fans subsequently authenticated and supplied telemetry.
|
|
9
|
+
- Kitchen Boost, cancellation, Pause and resume passed live HAP trials, including recovery of pending commands without another tap. Its Boost setting remains 2450 RPM.
|
|
10
|
+
- Wetroom rejected 2450 RPM, returning Pause instead. A 2400 RPM per-fan requested-target ceiling passed ordinary Boost, cancellation, Pause, resume and a 100% slider request. Measured RPM is not capped or replaced by the requested percentage.
|
|
11
|
+
- Transient command failures retry with the latest intent retained across child restarts. Explicit rejection or incompatible readback stops retrying. Siri may time out while a request is still pending; switching the relevant override off replaces that pending request.
|
|
12
|
+
- Final readbacks at 13:16 UTC: Kitchen Active 1 / measured 93%; Wetroom Active 1 / measured 38%; both Boost and Pause Off, neither fan had a persisted pending request. Kitchen's high automatic reading is recorded without attributing its cause to a humidity or other trigger.
|
|
13
|
+
- These are observed control trials, not proof of uninterrupted Bluetooth reliability. Background measurements expire after 45 seconds; failed commands and invalid/authentication responses fault immediately.
|
|
14
|
+
|
|
15
|
+
## Initial read-only findings
|
|
16
|
+
|
|
17
|
+
- Installed plugin: 2.5.0-beta.1, confirmed by package metadata and Homebridge UI.
|
|
18
|
+
- Wetroom Fan configuration contains only `name` and `pin`. PIN is a six-character string; no MAC address is configured. Startup explicitly reports `FAN_ADDRESS_REQUIRED`. Its cached accessory remains present with fan, Boost and Pause services.
|
|
19
|
+
- Kitchen Fan configuration contains `name`, `mac` and `pin`. Address format is valid and PIN is an eight-character string. Successful snapshot publication is evidenced by communication-restored messages, followed by transport failures and stale telemetry.
|
|
20
|
+
- Latest observed SvaraHome log event was `BLE_RECOVERY_REQUIRED` at 09:25:50. Home screenshots around 09:27 show switch values and fan tiles Updating; those screenshots alone do not demonstrate fresh telemetry or working controls.
|
|
21
|
+
- Adapter read returned RX/TX error counters of zero and an existing LE connection. This establishes neither a healthy GATT session nor ownership of that connection.
|
|
22
|
+
- No evidence warrants a whole-Pi power cycle as the first remedy. Wetroom's missing binding must be resolved separately. Kitchen requires investigation of disconnect/recovery behaviour.
|
|
23
|
+
|
|
24
|
+
## Observed fan log sequence
|
|
25
|
+
|
|
26
|
+
| Local time | Event |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| 09:22:19 | FAN_ADDRESS_REQUIRED; initial BLUETOOTH_NOT_READY |
|
|
29
|
+
| 09:22:23 | Communication restored |
|
|
30
|
+
| 09:23:23 | BLE_OPERATION_FAILED; BLE_RECOVERY_REQUIRED |
|
|
31
|
+
| 09:24:00 | TELEMETRY_STALE |
|
|
32
|
+
| 09:24:03 | BLE_RECOVERY_REQUIRED |
|
|
33
|
+
| 09:24:46 | Communication restored |
|
|
34
|
+
| 09:25:10 | BLE_OPERATION_FAILED |
|
|
35
|
+
| 09:25:20 | BLE_RECOVERY_REQUIRED |
|
|
36
|
+
| 09:25:44 | TELEMETRY_STALE |
|
|
37
|
+
| 09:25:50 | BLE_RECOVERY_REQUIRED |
|
|
38
|
+
|
|
39
|
+
The logs do not identify the fan per event. Attribution of transport activity to Kitchen follows from Wetroom being excluded during configuration validation; it is an inference, rather than an explicit log label.
|
|
40
|
+
|
|
41
|
+
## Source inspection
|
|
42
|
+
|
|
43
|
+
Transport serializes sessions and refuses a new one while a prior connection is unresolved or its peripheral is not disconnected. Disconnect is attempted in the session's finally block. If it times out, subsequent attempts only check the recovery gate; they do not actively retry disconnect. This can leave polling blocked indefinitely. The underlying first BLE error is reduced to a generic code, so these observations do not establish its cause.
|
|
44
|
+
|
|
45
|
+
Fan and switch services are present in the persisted cache. Home's displayed switch names do not distinguish Boost from Pause despite distinct service names in that cache; this is a separate usability issue to investigate.
|
|
46
|
+
|
|
47
|
+
No PIN values or full Bluetooth addresses are retained here.
|
|
48
|
+
|
|
49
|
+
## Local hotfix and follow-up
|
|
50
|
+
|
|
51
|
+
The owner authorised correction. A private backup of the original configuration and changed plugin files was created on the Pi at `svarahome-hotfix-backup-20261025-093309`. Wetroom's missing address was filled from the single unmatched cached accessory after checking that exactly one configured fan lacked an address. Fan identities and PIN values were preserved.
|
|
52
|
+
|
|
53
|
+
Local hotfix changes (not yet a published npm release):
|
|
54
|
+
|
|
55
|
+
- Retry a stalled disconnect before the next session, continuing to block new connections if recovery cannot be confirmed.
|
|
56
|
+
- Avoid disconnecting a peripheral already reported disconnected; Noble otherwise changes it back to disconnecting and may wait for an event that will never arrive.
|
|
57
|
+
- Await acknowledged scan stop before connecting or handing the radio to the next session.
|
|
58
|
+
- Supply explicit ConfiguredName values for Boost and Pause and identify each accessory in recovery/error logs.
|
|
59
|
+
|
|
60
|
+
All 48 tests pass across Node 22/24 and Homebridge 1/2. These include stalled-disconnect recovery, failure to recover, dropped connections, acknowledged scan stop, scan-stop timeout, transient background failures with a strict freshness limit, automatic command retries, supersession, restart persistence, lost-confirmation timer preservation, protected writes after authentication processing and per-fan target limits with uncapped measured telemetry.
|
|
61
|
+
|
|
62
|
+
Both modified files were hash checked against locally tested source before deployment. SvaraHome's child bridge alone was restarted to activate each hotfix stage. No whole-Pi reboot or fan control/configuration command was issued by the diagnostic workflow. Existing configured quiet-hours behaviour remains part of normal plugin polling.
|
|
63
|
+
|
|
64
|
+
At 09:35, passive monitoring observed 182 Kitchen address mentions and zero Wetroom address mentions over 16 seconds, plus two scan-enable Command Disallowed responses. Neither configured fan had an existing Pi LE connection at the start of that observation.
|
|
65
|
+
|
|
66
|
+
The owner then confirmed the official app was open and would close it. Subsequent logs show Wetroom AUTH_REJECTED at 09:36:12 and Kitchen communication restored at 09:36:16. At 09:36:55 no newer Kitchen fault had been logged. This supports renewed Kitchen communication; it is not yet sustained reliability validation.
|
|
67
|
+
|
|
68
|
+
The owner subsequently confirmed Wetroom's saved PIN was incorrect and was directed to correct it privately in Homebridge Plugin Config. The user was editing that form during follow-up; automation yielded to avoid interfering with credential entry.
|
|
69
|
+
|
|
70
|
+
Final deployed hotfix source fingerprints:
|
|
71
|
+
|
|
72
|
+
- `lib/transport.js`: `5c4220af7c69629859427b0250e248ae6359353286eacbe635c710ccbc9ae051`
|
|
73
|
+
- `lib/accessory.js`: `a3bfc5ded2fa2fb2a08b1e3eadfb45231924024ec402d86de787ce8f4f6ed2bb`
|
|
74
|
+
- `lib/platform.js`: `395db1bafe8f9d2a5fd6618ee62ced7da38afb1da4a49088882bfbb20b31ced4`
|
|
75
|
+
- `config.schema.json`: `764cb5a906cfdd0b993a7574e4b42ef1b2cad90c54849c05ec5045334ca80189`
|
|
76
|
+
|
|
77
|
+
The child bridge restart was requested after the second source update; final live verification remains pending after the owner's configuration edit.
|
|
78
|
+
|
|
79
|
+
The owner confirmed the correct Wetroom PIN was saved and the bridge restarted. At 09:40:43 both installed source hashes matched the tested final hotfix. The latest logs showed Wetroom communication restored at 09:40:10 and Kitchen restored at 09:40:14. No newer failures were present at that check. Earlier Kitchen errors at 09:38:16 and 09:39:36 recovered automatically at 09:38:30 and 09:39:49 respectively; this validates retry recovery in operation, while intermittent failures still require investigation. No unsupported claim of sustained reliability is made.
|
|
80
|
+
|
|
81
|
+
A subsequent 45-second passive observation saw successful connections alongside Remote User Terminated Connection and Connection Timeout events, and scan-enable Command Disallowed statuses. Attribute Not Found messages during service discovery are not themselves evidence of a failed user operation. The capture establishes intermittent link/controller events, but not their physical cause.
|
|
82
|
+
|
|
83
|
+
The final hotfix also retains the last verified snapshot during retryable background-poll failures only while it is under 45 seconds old. Authentication failures, invalid telemetry and failed user commands still fault immediately. No optimistic command success is introduced. Final accessory source was hash checked and activated by terminating only the confirmed SvaraHome child process via a pidfd; Homebridge supervises its restart. This last update supersedes the accessory fingerprint used for the 09:40:43 check above.
|
|
84
|
+
|
|
85
|
+
The owner then explicitly required pending Boost requests to retry patiently while tiles remain truthful. The working change persists the newest manual request in accessory context and retries transient failures every ten seconds after each failed attempt, across child restarts. A newer manual command supersedes it before any older queued write. Rejected authentication, invalid data and unsupported modes stop retries. Siri's own timeout cannot be extended by the plugin: Siri may report failure while the request remains pending, and a pending request can start when connectivity returns later. Users cancel pending Boost/Pause by switching that control off. Lost write responses are reconciled before resending so an already-running timer is not repeatedly extended. HAP's requested speed cache is replaced with measured readback after the set callback. The accessory fingerprint above now refers to this pending-command revision; live activation and its outcome are recorded below when complete.
|
|
86
|
+
|
|
87
|
+
## HomeKit switch trials after pending-retry activation
|
|
88
|
+
|
|
89
|
+
Revision c8142f1 was hash checked and activated at 12:25. Both fans subsequently appeared On with both overrides Off in Homebridge's HAP accessory UI.
|
|
90
|
+
|
|
91
|
+
- Kitchen Boost: request became pending at 12:28:37, later showed Boost On with measured speed 96%; switching Boost Off returned it to automatic ventilation.
|
|
92
|
+
- Kitchen Pause: request became pending at 12:30:00, later showed Pause On, Active 0, measured speed 0%, CurrentFanState Idle. Switching Pause Off returned the fan to On with both switches Off.
|
|
93
|
+
- Wetroom Boost at configured 2450 RPM: request became pending at 12:31:49, repeatedly returned COMMAND_NOT_CONFIRMED, and readback showed Pause On rather than Boost. A Pause Off command superseded the pending request; the subsequent cache inspection showed no pending request for either fan. This is a failed compatibility test, not a successful Boost result.
|
|
94
|
+
|
|
95
|
+
The working revision now stops retries after an explicitly different valid control readback and records requested/received manual state, RPM and seconds for diagnosis. Transport errors and lost responses remain retryable. A 200 ms authentication processing interval is being tested, based on the upstream [WhisperBridge Svara implementation](https://garethcooke.github.io/WhisperBridge/). Its documentation reports silently ignored command writes without this interval; applicability to the owner's older fan remains a hypothesis until live testing.
|
|
96
|
+
|
|
97
|
+
Revision 4abd47d was activated at 12:45:25. At 12:46:48 Wetroom still returned `requested boost 2450 RPM/600s, received pause 0 RPM/599s`. The authentication processing interval therefore did not resolve this speed-specific failure. The request stopped rather than repeatedly resending the mismatched control state.
|
|
98
|
+
|
|
99
|
+
The Homebridge UI fan tile toggles Active rather than exposing a speed slider. A temporary Pause from that inspection was cleared through the bridge's existing authenticated HAP interface. The QA-checked `tools/pi-hap-probe.py` verifies accessory ID and exact service name before writing, reads the existing bridge PIN locally without printing it, and connects only to the configured loopback HAP port. It does not change authentication or enable an insecure listener.
|
|
100
|
+
|
|
101
|
+
Wetroom then accepted a 96% slider request (2400 RPM target) with HTTP 204 and measured readbacks of 84%, 99%, 99%, Boost 1 and Pause 0. Boost-off returned HTTP 204 and measured readbacks of 75%, 40%, 40%, with both overrides Off. This distinguishes the accepted 2400 RPM target from the rejected 2450 RPM target; it does not establish an exact firmware-wide maximum.
|
|
102
|
+
|
|
103
|
+
The candidate now provides optional per-fan `maxManualRpm` validation and UI input, applying the ceiling to Boost and slider targets while leaving measured RPM unchanged. Wetroom was assigned the validated 2400 RPM ceiling; Kitchen's common Boost setting remains unchanged.
|
|
104
|
+
|
|
105
|
+
## Final configuration activation and trials
|
|
106
|
+
|
|
107
|
+
Revision `9f30baeb7c0f4eeeefb7c6f3e33bbbc7b4b76424` was hash checked and installed at 13:04. A direct child-process restart loaded the changed source but retained the parent's earlier configuration: the 13:08:44 log explicitly reported a 2450 RPM target despite the 2400 RPM value on disk. This failed trial returned HTTP 207 / HAP -70402 and correctly displayed Pause, measured 0%, rather than Boost. Pause-off returned HTTP 204 and restored automatic ventilation (48%, 48%, 39%). The deployment banner alone was therefore insufficient evidence of configuration activation.
|
|
108
|
+
|
|
109
|
+
The SvaraHome plugin's **Restart Child Bridge** action in Homebridge UI was then used to reload its configuration. The next ordinary Boost request returned HTTP 204, Boost On, Pause Off and measured readings of 93%, 95%, 95%. Boost-off returned HTTP 204, both override switches Off and measured readings of 95%, 38%, 41%. The measured speed was allowed to settle naturally instead of being forced to the requested slider value.
|
|
110
|
+
|
|
111
|
+
Wetroom Pause-on returned HTTP 204, Active 0, Pause On, Boost Off and three measured readings of 0%. Pause-off returned HTTP 204, Active 1, both overrides Off and measured readings of 56%, 56%, 41%.
|
|
112
|
+
|
|
113
|
+
A 100% Wetroom slider request returned HTTP 204, Boost On, Pause Off and measured readings of 93%, 96%, 96%. The requested target was capped by the per-fan limit; the displayed measurement was not pinned to the requested 100%.
|
|
114
|
+
|
|
115
|
+
Final Boost-off returned HTTP 204 and measured readings of 77%, 39%, 41%, with both overrides Off. Read-only checks at 13:16:16 UTC returned Kitchen Active 1, measured 93%, Boost 0, Pause 0; Wetroom Active 1, measured 38%, Boost 0, Pause 0. Both persisted accessory contexts had no pending manual request. Kitchen's elevated automatic speed was not diagnosed by these checks.
|
|
116
|
+
|
|
117
|
+
The final probe recorded 42 redacted events, retained on the Pi as `/var/lib/homebridge/svarahome-live-evidence-20261025.jsonl` (SHA-256 `9f5448e4bb0a51b0300f43a1b4d2ac0913a89a81fe79db7198fe1debd8cd3512`). No PIN, full Bluetooth address or complete configuration is included.
|
|
118
|
+
|
|
119
|
+
Source validation for this revision passed all four Linux Node 22/24 and Homebridge 1/2 jobs: [GitHub Actions run 40195658845](https://github.com/KernowekConsulting/homebridge-pax-calima/actions/runs/40195658845). Each combination passed 48 tests. Live outcomes remain separate evidence from those automated checks.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Stable 2.5.0 promotion checks
|
|
2
|
+
|
|
3
|
+
The owner has chosen to hold the homepage-button correction for full 2.5.0. There is no authorisation here to publish 2.4.6 or promote a beta to `latest`.
|
|
4
|
+
|
|
5
|
+
## Why the button differs during beta
|
|
6
|
+
|
|
7
|
+
Homebridge UI's `getPluginFromNpm` obtains the package at `/homebridge-pax-calima/latest`, then uses that package's `homepage` and `bugs.url` for its links. Choosing a newer beta for update detection does not replace those metadata fields. The installed version can therefore be beta.2 while the homepage button still uses stable 2.4.5's old GitHub address.
|
|
8
|
+
|
|
9
|
+
Verified on the owner's Pi on 25 October: installed version 2.5.0-beta.2; Plugin Homepage target `https://github.com/JayC68/homebridge-pax-calima`. The public beta.2 package has the intended website URL. Source: [Homebridge UI plugins service](https://github.com/homebridge/homebridge-config-ui-x/blob/latest/src/modules/plugins/plugins.service.ts).
|
|
10
|
+
|
|
11
|
+
The same service locates GitHub release notes from either the homepage or issue-tracker URL. With a separate website homepage, retain the GitHub issue tracker. Repository metadata must also use the current organisation.
|
|
12
|
+
|
|
13
|
+
## Prepare the stable build
|
|
14
|
+
|
|
15
|
+
- Set package and lockfile versions to `2.5.0`.
|
|
16
|
+
- Use homepage `https://homebridge.svarahome.kernowekconsulting.co.uk`.
|
|
17
|
+
- Use issue tracker `https://github.com/KernowekConsulting/homebridge-pax-calima/issues`.
|
|
18
|
+
- Use repository `git+https://github.com/KernowekConsulting/homebridge-pax-calima.git`.
|
|
19
|
+
- Keep setup/support website links on the SvaraHome site. GitHub issue, release, source, Homebridge requirement and dependency-reference links have distinct purposes and must retain their appropriate destinations.
|
|
20
|
+
- Check all relative Markdown links against the shipped files and repository tree. The linked redacted live report and trial records are now on the package allowlist.
|
|
21
|
+
- Inspect README.md inside the exact stable tarball. It must contain the cleaned 2.5 guide: Fan, Boost Fan, optional Pause Fan and optional saved-schedule Silent Hours. Reject the obsolete claims of live temperature, ambient humidity/light, guaranteed live/accurate speed, an actionable Boost event button, or child-bridge accessories being unavailable in Homebridge UI. No fixed sensor-update interval or unsupported shower-detection claim may remain.
|
|
22
|
+
- Review the concise 2.5 RELEASE_NOTES.md and CHANGELOG.md against the final behaviour and the changes since 2.4.5. Communicate only added value, changes and essential upgrade steps: no beta discussion, internal workings, investigations or test chronology. Remove the Unreleased label when publishing; existing prerelease tags/releases retain development history. Replace the README’s short beta-installation notice with the stable installation instructions.
|
|
23
|
+
- Reconcile the latest beta acceptance evidence, including Siri with the owner's actual Home names, reconnection, expiry/cancellation and extended operation. Record limits honestly; automated HAP trials do not establish voice recognition or uninterrupted Bluetooth reliability.
|
|
24
|
+
- Run the Node 22/24 × Homebridge 1/2 checks, native install/load check, full/production audits and package checks on the exact release commit. Verify public source, issues and matching release notes.
|
|
25
|
+
- Confirm that the new site resolves and responds over HTTPS. The earlier beta.2 check failed DNS resolution; the intended page subsequently loaded over HTTPS in Safari during beta.3 publication. Recheck the live destination at stable promotion.
|
|
26
|
+
|
|
27
|
+
## Verify the published result
|
|
28
|
+
|
|
29
|
+
Only perform the promotion when the owner requests it.
|
|
30
|
+
|
|
31
|
+
- Publish the tested stable package, matching GitHub release and tag. Ensure the repository's default branch contains the stable source/docs reviewers will inspect.
|
|
32
|
+
- Read npm's `latest` endpoint: version must be `2.5.0` and all three URLs above must match. Download the public tarball and compare its checksum and metadata with the checked artifact.
|
|
33
|
+
- Open the public default npm page https://www.npmjs.com/package/homebridge-pax-calima and inspect its rendered README after registry/site propagation. Confirm it shows the cleaned 2.5 guide and none of the obsolete claims listed above. Verify the public tarball's README matches the reviewed release source. Do not declare the documentation cleanup complete on the strength of GitHub alone; save the public npm result in release evidence.
|
|
34
|
+
- Allow Homebridge's registry metadata cache to refresh (the upstream service uses a five-minute package cache), then refresh the plugin page. A whole-Pi reboot is unnecessary for this check.
|
|
35
|
+
- Open SvaraHome's Plugin Information modal and inspect **PLUGIN HOMEPAGE** itself. It must point to the requested site; following it must load the intended page.
|
|
36
|
+
- Verify Homebridge's release-note/changelog view resolves the matching GitHub notes and that the website support link works. Inspect the issue-tracker and repository destinations separately.
|
|
37
|
+
- Save actual link targets and results in the release evidence. Registry metadata alone is insufficient acceptance evidence for the UI button.
|
|
38
|
+
- Reassess docs/VERIFICATION.md, then prepare a verification request with the approved 100 × 100 icon. Submitting it is a separate external communication requiring the owner's instruction.
|
package/docs/VALIDATION.md
CHANGED
|
@@ -1,61 +1,35 @@
|
|
|
1
|
-
# 2.5
|
|
1
|
+
# SvaraHome 2.5 validation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Current code evidence
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The runtime on the default branch is the tested beta.3 implementation (release commit 3f4066177868d7a651c8400803c3f490f21d471b). Later repository cleanup changes documentation, not runtime behaviour.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
All 52 tests passed in each Node 22/24 × Homebridge 1/2 combination in [release CI run 40220445646](https://github.com/KernowekConsulting/homebridge-pax-calima/actions/runs/40220445646). The jobs also passed native installation/loading, full and production security audit gates, syntax and package checks.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Coverage includes confirmed authentication, malformed telemetry, temporary control readback, timer expiry, queued BLE work, timeouts/disconnect recovery, pending-request retries and supersession, restart persistence, per-fan speed ceilings, preserved accessory/service identities and quiet-hours schedule continuity. Tests use real Homebridge services and maintained Noble classes with simulated physical Bluetooth bindings.
|
|
10
10
|
|
|
11
|
+
The four beta.3 additions cover default Fan/Boost Fan presentation with optional Pause Fan; main Fan Off starting a timed pause; Fan On clearing either override without changing persistent presets; persisted return-to-automatic after a connection failure/restart; and an ignored cancellation that must remain a communication fault.
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
The README configuration example was checked against runtime configuration validation. Relative links in packaged documentation and the logo path were checked during repository cleanup. Those checks do not establish Siri recognition or physical fan behaviour.
|
|
13
14
|
|
|
14
|
-
##
|
|
15
|
+
## Physical evidence
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
The owner’s newer eight-digit-PIN Kitchen fan and older six-digit-PIN Wetroom fan both authenticated and provided telemetry after configuration was corrected privately. Live HAP trials confirmed timed Boost, Pause and cancellation. Kitchen pending requests recovered without repeating the command. Earlier serial device trials also covered native expiry, early resume and speed changes.
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|---|---|---|
|
|
20
|
-
| 22.23.4 | 1.11.4 | 32/32 |
|
|
21
|
-
| 22.23.4 | 2.4.0 | 32/32 |
|
|
22
|
-
| 24.19.0 | 1.11.4 | 32/32 |
|
|
23
|
-
| 24.19.0 | 2.4.0 | 32/32 |
|
|
19
|
+
Wetroom accepted a 2400 RPM requested target but returned a zero-RPM override for 2450 RPM. Its per-fan ceiling was set to the accepted target; this is not a universal firmware limit. The final trial set ended with both manual overrides Off and no pending requests. See the [detailed dated report](BETA1-LIVE-DIAGNOSTIC.md) and [42 redacted final-trial records](pi-live-control-evidence-20261025.jsonl).
|
|
24
20
|
|
|
25
|
-
|
|
21
|
+
Beta.3’s new presentation and universal Fan On path have automated service-level coverage. No new physical beta.3 control trial or successful Siri voice acceptance is claimed by that evidence.
|
|
26
22
|
|
|
27
|
-
|
|
23
|
+
## Remaining acceptance and practical limits
|
|
28
24
|
|
|
29
|
-
|
|
25
|
+
- Test the actual Home names/Siri phrases, renamed controls and default visibility in the owner’s Home.
|
|
26
|
+
- Exercise Fan On from both Pause and Boost on both physical fans, then observe normal operation/recovery over a longer period before stable promotion.
|
|
27
|
+
- Temporary controls require operating mode 00; the plugin does not change installation modes. Nonzero targets below 1000 RPM are not offered.
|
|
28
|
+
- Status is measured RPM, not independent airflow. Temperature, humidity and light are not exposed as ambient sensors, and fan speed is not treated as proof of a shower or humidity event.
|
|
29
|
+
- A missed background poll may retain its last verified reading only within 45 seconds. Failed commands and invalid/stale telemetry fault. Acknowledged writes may still report failure if subsequent confirmation/telemetry is lost.
|
|
30
|
+
- Temporary connection failures retain the newest manual request, which can run later. Siri’s timeout does not cancel it. Authentication rejection, invalid data, incompatible readback and unsupported modes stop retries.
|
|
31
|
+
- Native quiet-hours behaviour depends on firmware/settings; its schedule enable/disable control is not an immediate-pause command.
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
## Historical records
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Earlier device trials on 24 October confirmed timed boost start/expiry/cancel/extend/speed adjustment and zero-RPM pause with expiry/early resume on the newer eight-digit-PIN Kitchen fan (software 02.10, mode 00). Those trials used diagnostic scripts, not this plugin implementation. They restored all captured settings exactly.
|
|
36
|
-
|
|
37
|
-
The older fan (software 02.08) did not confirm authentication using the attempted bindings; no older control tests ran. This build fixes routing and refusal to act without confirmation. It cannot establish that the currently saved older PIN is correct.
|
|
38
|
-
|
|
39
|
-
## Remaining acceptance gates
|
|
40
|
-
|
|
41
|
-
1. Native Linux installation/load is complete on the Pi: Linux ARM64, Node 24.22.1 and isolated Node 22.23.4, with the adapter left uninitialised. Full, production, Linux resolution, consumer and Pi audits report zero vulnerabilities. See DEPENDENCY-SECURITY.md. This verifies dependency installation/loading, not live fan control.
|
|
42
|
-
2. Save/reload Plugin Config on the Pi, securely correct the older fan's address/PIN, and confirm six/eight-digit routing without exposing either PIN in evidence.
|
|
43
|
-
3. Deploy the candidate deliberately to the fan child bridge, retaining the existing installed package for rollback. Confirm normal authenticated polling and invalid-PIN fault behavior.
|
|
44
|
-
4. In Apple Home, exercise Boost, Pause, early resume, timer expiry and slider control. Check mutual exclusion, command rejection/offline presentation and the expected service migration. Verify Siri using actual Home names/scenes.
|
|
45
|
-
5. Restart the fan child bridge during an active timed override, confirm readback restores the switches and let the native timer finish. Give bridge restoration a bounded independent fallback for any diagnostic interruption.
|
|
46
|
-
6. Confirm official-app changes are read and routine polls leave presets/schedules alone. Validate environmental/schedule behavior separately before expanding those claims.
|
|
47
|
-
7. Finalise the draft release copy, publish the accepted npm package with a matching GitHub release, then request Homebridge verification/icon registration.
|
|
48
|
-
|
|
49
|
-
## Known limits
|
|
50
|
-
|
|
51
|
-
No independent airflow measurement, final Apple Home/Siri test or live 2.5.0 deployment has occurred. Durations default to ten minutes and are configurable from one to sixty; native timer serialization is tested, but long-duration physical acceptance still belongs in the final run. Manual controls require mode 00 and never change operating mode. Nonzero targets below 1000 RPM are not offered. Ambient sensors remain omitted until their interpretation is established.
|
|
52
|
-
|
|
53
|
-
A command acknowledged by the fan can still be reported failed if subsequent telemetry is invalid or communication is lost. This is deliberate uncertainty reporting; the next successful poll reconciles the fan, without automatically resending a control command.
|
|
54
|
-
|
|
55
|
-
## Owner-supplied Wetroom evidence
|
|
56
|
-
|
|
57
|
-
The 25 October official-app About screen identifies Wetroom Fan, Bathroom Mode, firmware 02.08, hardware 02.00 and app 7.3.0. See WETROOM-ABOUT.md. This does not establish authentication or control success. Approved beta copy and the stable-promotion rule are recorded in RELEASING.md.
|
|
58
|
-
|
|
59
|
-
## GitHub release checks
|
|
60
|
-
|
|
61
|
-
The Linux GitHub workflow passed native installation/loading, full and production security audits, syntax checks, all 32 tests and package-content checks in all four Node/Homebridge combinations. Run: https://github.com/KernowekConsulting/homebridge-pax-calima/actions/runs/40179681093. This confirms Linux installation and automated behavior, not physical fan/Apple Home acceptance.
|
|
35
|
+
The raw audits, install logs, fixtures and TAP outputs retained in this directory describe the builds named in those files. Older 32-test and 48-test snapshots do not replace the current 52-test release result. Earlier uncompleted checks in dated reports should be read alongside subsequent outcomes, rather than repeated as current blockers.
|
package/docs/VERIFICATION.md
CHANGED
|
@@ -1,47 +1,53 @@
|
|
|
1
|
-
# Homebridge verification
|
|
1
|
+
# Homebridge verification readiness
|
|
2
2
|
|
|
3
|
-
Reviewed
|
|
3
|
+
Reviewed 26 October 2026 against the current requirements and request forms. SvaraHome is not verified, and no verification request has been submitted by this work.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Assessment
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- [Current requirements](https://github.com/homebridge/plugins/wiki/Verified-Plugins), updated 5 May 2026; the older homebridge/homebridge wiki still quotes obsolete Node versions.
|
|
9
|
-
- [Verification process](https://github.com/homebridge/plugins#plugin-verification)
|
|
10
|
-
- [Verification form](https://github.com/homebridge/plugins/blob/latest/.github/ISSUE_TEMPLATE/1_verification-request.yml)
|
|
11
|
-
- [Icon form](https://github.com/homebridge/plugins/blob/latest/.github/ISSUE_TEMPLATE/2_icon-request.yml)
|
|
7
|
+
**The 2.5 candidate has evidence for the main technical requirements. Finish stable promotion and the remaining user acceptance checks before submitting.** The repository default branch now contains the tested 2.5 implementation and its current public guide. npm latest still points to the older stable release until the owner requests full promotion; that older package is not the remediated candidate.
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
| Requirement | Evidence and status |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| Dynamic platform | Implemented: PaxCalima registers a platform, restores cached fan identities and registers configured fans after launch. |
|
|
12
|
+
| Distinct functionality | No Pax, Calima or Svara name was found in the current verified list. This is a preliminary name check, not proof of a complete functionality comparison; explain support for these BLE fans and let reviewers assess overlap. |
|
|
13
|
+
| npm and public GitHub source, issues enabled | Confirmed: public KernowekConsulting repository with issues enabled. Beta.3 is published on npm with a matching GitHub prerelease and notes. Default-branch source now matches the 2.5 implementation; align version metadata and final copy at stable promotion. |
|
|
14
|
+
| Supported Node LTS versions | Beta.3 release commit 3f40661 passed all four Node 22/24 × Homebridge 1/2 jobs, 52 tests per job, including native installation/loading. |
|
|
15
|
+
| Installs and waits for configuration | Candidate has no install/postinstall script. Unconfigured or unusable fan configuration does not load Noble or start discovery. Native Linux ARM64 installation/loading was checked under Node 22/24; normal installed-plugin fan communication subsequently passed live checks. |
|
|
16
|
+
| No TTY or unusual Homebridge startup flags | Runtime has no TTY prompt or startup-flag dependency. Normal installed child-bridge operation is evidenced on the Pi. The radio still requires normal Bluetooth access; historical diagnostic scripts are not installation requirements. |
|
|
17
|
+
| Settings GUI | Schema provides explicit fan address/PIN, durations, switch visibility, quiet hours and per-fan speed limits. User PIN correction, saved configuration reload and the 2400 RPM setting were exercised in the actual UI/live plugin. |
|
|
18
|
+
| No tracking | Runtime source contains no analytics or HTTP/cloud requests. It communicates locally over BLE. |
|
|
19
|
+
| Homebridge-local storage | Runtime persists identity, schedule metadata and pending manual intent through Homebridge accessory context. It does not create separate runtime files elsewhere. Diagnostic evidence files are developer tools, not plugin runtime storage. |
|
|
20
|
+
| Caught errors | Implemented bounded BLE operations, caught polling/intent failures, redacted fan-specific logs and HomeKit communication errors. Tests cover rejected authentication, bad telemetry, timeouts, shutdown, retries and incompatible readback. This is evidence from inspected paths and tests, not a claim that no unforeseen defect can occur. |
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
The current [official requirements](https://github.com/homebridge/plugins/wiki/Verified-Plugins) specify Node 22 and 24 and were last revised on 5 May 2026. [The verification process](https://github.com/homebridge/plugins#plugin-verification) requires an issue using [the request form](https://github.com/homebridge/plugins/blob/latest/.github/ISSUE_TEMPLATE/1_verification-request.yml). The source of the orange shield is Homebridge's central verification status; it cannot be changed by adding a logo or a package field.
|
|
23
|
+
|
|
24
|
+
## Beta.3 update
|
|
25
|
+
|
|
26
|
+
Beta.3 simplifies the default presentation to Fan and Boost Fan; Pause Fan is optional and explicitly enabled settings are retained. Main Fan On now clears either override through the same verified, persisted request path. All 52 tests passed in each supported Node/Homebridge CI combination in [run 40220445646](https://github.com/KernowekConsulting/homebridge-pax-calima/actions/runs/40220445646). The checked public beta.3 tarball matched its recorded checksum. This extends automated evidence, not the earlier physical/Siri acceptance evidence below.
|
|
16
27
|
|
|
17
|
-
|
|
18
|
-
|---|---|
|
|
19
|
-
| Dynamic platform | Registers PaxCalima, restores cached identities and creates only explicitly configured fans after launch. |
|
|
20
|
-
| Node LTS | 32 tests pass on Node 22.23.4 and 24.19.0 with Homebridge 1.11.4 and 2.4.0. |
|
|
21
|
-
| Settings GUI | Schema provides per-fan addresses and secret six/eight-digit PIN fields, Boost/Pause choices and quiet hours. Actual UI save/reload still needs acceptance testing. |
|
|
22
|
-
| Configuration gate | No Noble load or radio work for absent/empty/unusable fan config; unroutable cached accessories remain faulted. |
|
|
23
|
-
| Errors | Bounded sessions, rejected-PIN polling stop, redacted messages and HomeKit communication errors; no optimistic success after rejected readback. |
|
|
24
|
-
| Storage/tracking | No runtime files outside Homebridge. Only schedule-application metadata is saved through accessory context. No analytics or cloud calls. |
|
|
25
|
-
| Installation/startup | Plugin has no install/postinstall script or TTY requirement. Noble native dependencies install/load successfully on the Pi under Node 22/24 without starting the adapter. Live Bluetooth access through the installed plugin still needs acceptance testing. |
|
|
26
|
-
| Dependency audit | The vulnerable Noble/native build chain has been replaced. All saved audits, including the Pi, report zero vulnerabilities. Native Linux ARM64 install/load passes on Node 22/24; actual fan communication remains an acceptance check. |
|
|
27
|
-
| Comparable verified plugin | Current list has no name matching Pax or Calima. A full functionality comparison and final decision remain with Homebridge reviewers. |
|
|
28
|
-
| Publication | Local candidate only. npm publication and matching GitHub release remain pending acceptance. |
|
|
28
|
+
## Earlier release evidence
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
- Exact beta.2 release CI: [run 40216171472](https://github.com/KernowekConsulting/homebridge-pax-calima/actions/runs/40216171472), all four jobs successful. Native module loading, full/production high-severity audit gates, syntax, tests and package checks passed.
|
|
31
|
+
- Published [npm beta.2](https://www.npmjs.com/package/homebridge-pax-calima/v/2.5.0-beta.2) and [matching GitHub prerelease](https://github.com/KernowekConsulting/homebridge-pax-calima/releases/tag/v2.5.0-beta.2).
|
|
32
|
+
- Public beta.2 tarball SHA-256: b1153a3c4a07463c900a5f2407383ecb9583cff983097b8849f062f20a5854fa. Registry download matched the checked artifact and its homepage/issue metadata.
|
|
33
|
+
- Both six- and eight-digit-PIN fans authenticated after the owner corrected Wetroom's saved PIN privately. Live HAP controls confirmed Boost, Pause and cancellation on both fans. Wetroom accepted the 2400 RPM ceiling and capped 100% slider request; 2450 RPM was explicitly rejected as a zero-RPM override.
|
|
34
|
+
- Kitchen transient failures recovered without repeating the Home command. Final trials ended with both manual overrides Off and no pending requests. See [the detailed live report](BETA1-LIVE-DIAGNOSTIC.md) and [42 redacted trial records](pi-live-control-evidence-20261025.jsonl).
|
|
35
|
+
- Dependency remediation and isolated installation details are in [DEPENDENCY-SECURITY.md](DEPENDENCY-SECURITY.md). The beta implementation uses the maintained Noble fork; stable 2.4.5 still has the old dependency.
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
## Remaining work before requesting review
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
1. Complete the owner's chosen full 2.5.0 promotion, including final version/source alignment, review of the concise user-facing release copy and removal of the changelog’s Unreleased label. The owner declined a metadata-only 2.4.6 release.
|
|
40
|
+
2. Follow [STABLE-PROMOTION.md](STABLE-PROMOTION.md): verify npm latest metadata, the actual Homebridge Plugin Homepage button and release-note view after cache refresh. Beta.2's homepage is correct, but the UI currently uses stable 2.4.5 metadata. Preserve a GitHub issue tracker so release-note discovery still works.
|
|
41
|
+
3. Verify that the requested SvaraHome website resolves and loads over HTTPS. It did not resolve during the earlier beta.2 check, but the intended site subsequently loaded over HTTPS in Safari during beta.3 publication. Recheck at stable promotion. This is a website acceptance issue, not a listed Homebridge verification criterion.
|
|
42
|
+
4. Record normal-use acceptance on both fans, including the owner's actual Siri names/scenes and a longer period of automatic operation/recovery. HAP tests do not establish Siri recognition or uninterrupted BLE reliability. These are our release acceptance checks, not additional formal Homebridge rules.
|
|
43
|
+
5. Prepare the verification form with accurate evidence and the approved icon, then submit only when the owner requests that communication. Review and approval remain with Homebridge.
|
|
35
44
|
|
|
36
|
-
|
|
45
|
+
## Logo
|
|
37
46
|
|
|
38
|
-
-
|
|
39
|
-
- repository: `https://github.com/KernowekConsulting/homebridge-pax-calima`
|
|
40
|
-
- attachment: `assets/homebridge-pax-calima.png`
|
|
41
|
-
- status: do not submit until the open validation and dependency items are resolved; the supplied manufacturer mark is subject to its owner's rights as explained alongside the asset.
|
|
47
|
+
The approved SvaraHome artwork is assets/svarahome-master.png, with a 1024-pixel version in assets/svarahome.png. assets/homebridge-pax-calima.png was checked as a square 100 × 100 PNG.
|
|
42
48
|
|
|
43
|
-
|
|
49
|
+
The verification form accepts an optional icon attachment. The [separate icon request form](https://github.com/homebridge/plugins/blob/latest/.github/ISSUE_TEMPLATE/2_icon-request.yml) requires an already-verified plugin and a request from its developer. Include the approved icon with the verification request; central registration controls its appearance in the Homebridge tile. Do not claim verification, use a verified badge or replace the approved logo with a manufacturer mark.
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
## Stable release preparation — 26 October 2026
|
|
46
52
|
|
|
47
|
-
|
|
53
|
+
The owner authorised stable 2.5.0 publication and a verification application. Stable release notes and the changelog describe value and changes since 2.4.5, without prerelease history. The owner also reported that Wetroom Boost Fan worked and subsequently returned to automatic operation; the elapsed duration was not measured. Exact Siri recognition and uninterrupted long-term Bluetooth operation are not claimed. Final stable CI, public npm metadata/tarball/README checks and verification submission are recorded separately in release evidence. The earlier remaining-work list is historical preparation, not a claim that those outcomes have already been completed.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{"at": "2026-10-25T13:08:41.323911+00:00", "aid": 2, "action": "boost-on", "requested_percent": null, "event": "BEFORE", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 39, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
2
|
+
{"at": "2026-10-25T13:08:44.429357+00:00", "aid": 2, "action": "boost-on", "requested_percent": null, "event": "REQUEST", "data": {"http": 207, "response": {"characteristics": [{"aid": 2, "iid": 27, "status": -70402}]}}}
|
|
3
|
+
{"at": "2026-10-25T13:08:54.445536+00:00", "aid": 2, "action": "boost-on", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 0, "status": 0}, "measured_percent": {"value": 0, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 1, "status": 0}}}
|
|
4
|
+
{"at": "2026-10-25T13:09:04.463256+00:00", "aid": 2, "action": "boost-on", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 0, "status": 0}, "measured_percent": {"value": 0, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 1, "status": 0}}}
|
|
5
|
+
{"at": "2026-10-25T13:09:14.479609+00:00", "aid": 2, "action": "boost-on", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 0, "status": 0}, "measured_percent": {"value": 0, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 1, "status": 0}}}
|
|
6
|
+
{"at": "2026-10-25T13:09:55.242002+00:00", "aid": 2, "action": "pause-off", "requested_percent": null, "event": "BEFORE", "data": {"active": {"value": 0, "status": 0}, "measured_percent": {"value": 0, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 1, "status": 0}}}
|
|
7
|
+
{"at": "2026-10-25T13:09:59.273218+00:00", "aid": 2, "action": "pause-off", "requested_percent": null, "event": "REQUEST", "data": {"http": 204, "response": {}}}
|
|
8
|
+
{"at": "2026-10-25T13:10:09.288432+00:00", "aid": 2, "action": "pause-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 48, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
9
|
+
{"at": "2026-10-25T13:10:19.308534+00:00", "aid": 2, "action": "pause-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 48, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
10
|
+
{"at": "2026-10-25T13:10:29.317172+00:00", "aid": 2, "action": "pause-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 39, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
11
|
+
{"at": "2026-10-25T13:11:06.347290+00:00", "aid": 2, "action": "boost-on", "requested_percent": null, "event": "BEFORE", "data": {"active": {"value": null, "status": -70402}, "measured_percent": {"value": null, "status": -70402}, "boost": {"value": null, "status": -70402}, "pause": {"value": null, "status": -70402}}}
|
|
12
|
+
{"at": "2026-10-25T13:11:11.042550+00:00", "aid": 2, "action": "boost-on", "requested_percent": null, "event": "REQUEST", "data": {"http": 204, "response": {}}}
|
|
13
|
+
{"at": "2026-10-25T13:11:21.059460+00:00", "aid": 2, "action": "boost-on", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 93, "status": 0}, "boost": {"value": 1, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
14
|
+
{"at": "2026-10-25T13:11:31.081613+00:00", "aid": 2, "action": "boost-on", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 95, "status": 0}, "boost": {"value": 1, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
15
|
+
{"at": "2026-10-25T13:11:41.098714+00:00", "aid": 2, "action": "boost-on", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 95, "status": 0}, "boost": {"value": 1, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
16
|
+
{"at": "2026-10-25T13:11:50.140075+00:00", "aid": 2, "action": "boost-off", "requested_percent": null, "event": "BEFORE", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 96, "status": 0}, "boost": {"value": 1, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
17
|
+
{"at": "2026-10-25T13:11:53.417810+00:00", "aid": 2, "action": "boost-off", "requested_percent": null, "event": "REQUEST", "data": {"http": 204, "response": {}}}
|
|
18
|
+
{"at": "2026-10-25T13:12:03.433787+00:00", "aid": 2, "action": "boost-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 95, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
19
|
+
{"at": "2026-10-25T13:12:13.452490+00:00", "aid": 2, "action": "boost-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 38, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
20
|
+
{"at": "2026-10-25T13:12:23.467440+00:00", "aid": 2, "action": "boost-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 41, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
21
|
+
{"at": "2026-10-25T13:12:40.913434+00:00", "aid": 2, "action": "pause-on", "requested_percent": null, "event": "BEFORE", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 41, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
22
|
+
{"at": "2026-10-25T13:12:44.572116+00:00", "aid": 2, "action": "pause-on", "requested_percent": null, "event": "REQUEST", "data": {"http": 204, "response": {}}}
|
|
23
|
+
{"at": "2026-10-25T13:12:54.581325+00:00", "aid": 2, "action": "pause-on", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 0, "status": 0}, "measured_percent": {"value": 0, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 1, "status": 0}}}
|
|
24
|
+
{"at": "2026-10-25T13:13:04.594261+00:00", "aid": 2, "action": "pause-on", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 0, "status": 0}, "measured_percent": {"value": 0, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 1, "status": 0}}}
|
|
25
|
+
{"at": "2026-10-25T13:13:14.961023+00:00", "aid": 2, "action": "pause-on", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 0, "status": 0}, "measured_percent": {"value": 0, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 1, "status": 0}}}
|
|
26
|
+
{"at": "2026-10-25T13:13:54.012053+00:00", "aid": 2, "action": "pause-off", "requested_percent": null, "event": "BEFORE", "data": {"active": {"value": 0, "status": 0}, "measured_percent": {"value": 0, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 1, "status": 0}}}
|
|
27
|
+
{"at": "2026-10-25T13:13:57.330279+00:00", "aid": 2, "action": "pause-off", "requested_percent": null, "event": "REQUEST", "data": {"http": 204, "response": {}}}
|
|
28
|
+
{"at": "2026-10-25T13:14:07.345068+00:00", "aid": 2, "action": "pause-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 56, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
29
|
+
{"at": "2026-10-25T13:14:17.363523+00:00", "aid": 2, "action": "pause-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 56, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
30
|
+
{"at": "2026-10-25T13:14:27.382880+00:00", "aid": 2, "action": "pause-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 41, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
31
|
+
{"at": "2026-10-25T13:14:42.713740+00:00", "aid": 2, "action": "speed", "requested_percent": 100, "event": "BEFORE", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 42, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
32
|
+
{"at": "2026-10-25T13:14:47.258084+00:00", "aid": 2, "action": "speed", "requested_percent": 100, "event": "REQUEST", "data": {"http": 204, "response": {}}}
|
|
33
|
+
{"at": "2026-10-25T13:14:57.273149+00:00", "aid": 2, "action": "speed", "requested_percent": 100, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 93, "status": 0}, "boost": {"value": 1, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
34
|
+
{"at": "2026-10-25T13:15:07.290418+00:00", "aid": 2, "action": "speed", "requested_percent": 100, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 96, "status": 0}, "boost": {"value": 1, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
35
|
+
{"at": "2026-10-25T13:15:17.312916+00:00", "aid": 2, "action": "speed", "requested_percent": 100, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 96, "status": 0}, "boost": {"value": 1, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
36
|
+
{"at": "2026-10-25T13:15:26.669639+00:00", "aid": 2, "action": "boost-off", "requested_percent": null, "event": "BEFORE", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 97, "status": 0}, "boost": {"value": 1, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
37
|
+
{"at": "2026-10-25T13:15:30.008850+00:00", "aid": 2, "action": "boost-off", "requested_percent": null, "event": "REQUEST", "data": {"http": 204, "response": {}}}
|
|
38
|
+
{"at": "2026-10-25T13:15:40.023216+00:00", "aid": 2, "action": "boost-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 77, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
39
|
+
{"at": "2026-10-25T13:15:50.038054+00:00", "aid": 2, "action": "boost-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 39, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
40
|
+
{"at": "2026-10-25T13:16:00.045582+00:00", "aid": 2, "action": "boost-off", "requested_percent": null, "event": "READBACK", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 41, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
41
|
+
{"at": "2026-10-25T13:16:16.442125+00:00", "aid": 3, "action": "read", "requested_percent": null, "event": "BEFORE", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 93, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
|
42
|
+
{"at": "2026-10-25T13:16:16.666743+00:00", "aid": 2, "action": "read", "requested_percent": null, "event": "BEFORE", "data": {"active": {"value": 1, "status": 0}, "measured_percent": {"value": 38, "status": 0}, "boost": {"value": 0, "status": 0}, "pause": {"value": 0, "status": 0}}}
|
package/lib/accessory.js
CHANGED
|
@@ -12,7 +12,8 @@ class FanAccessory {
|
|
|
12
12
|
this.pollPending = false; this.errorCode = null; this.controls = [];
|
|
13
13
|
this.intent = null;
|
|
14
14
|
const saved = accessory.context.pendingManual;
|
|
15
|
-
if (saved && ['boost', 'pause'].includes(saved.kind) && typeof saved.on === 'boolean' &&
|
|
15
|
+
if (saved && ['boost', 'pause', 'automatic'].includes(saved.kind) && typeof saved.on === 'boolean' &&
|
|
16
|
+
(saved.kind !== 'automatic' || (saved.on === false && saved.rpm === undefined)) &&
|
|
16
17
|
(saved.rpm === undefined || (Number.isInteger(saved.rpm) && saved.rpm >= 1000 && saved.rpm <= MAX_RPM && saved.rpm % 25 === 0))) {
|
|
17
18
|
this.intent = { kind: saved.kind, on: saved.on, rpm: saved.rpm, attempted: saved.attempted === true };
|
|
18
19
|
}
|
|
@@ -44,7 +45,7 @@ class FanAccessory {
|
|
|
44
45
|
this.fanService = a.getService(S.Fanv2) || a.addService(new S.Fanv2(name, 'fan'));
|
|
45
46
|
this.fanService.setPrimaryService(true);
|
|
46
47
|
this.characteristic(this.fanService, C.Active, s => s.manual.state === 'pause' ? 0 : Number(s.status.rpm > 0),
|
|
47
|
-
value => { check(value === 0 || value === 1, 'INVALID_COMMAND'); return value === 0 ? this.manual('pause', true) : this.manual('
|
|
48
|
+
value => { check(value === 0 || value === 1, 'INVALID_COMMAND'); return value === 0 ? this.manual('pause', true) : this.manual('automatic', false); });
|
|
48
49
|
this.characteristic(this.fanService, C.RotationSpeed, s => Math.round(s.status.rpm / 25),
|
|
49
50
|
percent => this.speed(percent)).setProps({ minValue: 0, maxValue: 100, minStep: 1 });
|
|
50
51
|
this.characteristic(this.fanService, C.CurrentFanState, s => s.status.rpm > 0 ? 2 : 1);
|
|
@@ -52,9 +53,9 @@ class FanAccessory {
|
|
|
52
53
|
for (const type of [S.StatelessProgrammableSwitch, S.TemperatureSensor, S.HumiditySensor, S.LightSensor]) {
|
|
53
54
|
for (const service of [...a.services]) if (service.UUID === type.UUID) a.removeService(service);
|
|
54
55
|
}
|
|
55
|
-
this.boostService = this.switchService('boost', 'Boost', this.config.showBoostSwitch !== false,
|
|
56
|
+
this.boostService = this.switchService('boost', 'Boost Fan', this.config.showBoostSwitch !== false,
|
|
56
57
|
s => s.manual.state === 'boost', value => this.manual('boost', value));
|
|
57
|
-
this.pauseService = this.switchService('pause', 'Pause', this.config.showPauseSwitch
|
|
58
|
+
this.pauseService = this.switchService('pause', 'Pause Fan', this.config.showPauseSwitch === true,
|
|
58
59
|
s => s.manual.state === 'pause', value => this.manual('pause', value));
|
|
59
60
|
this.silentService = this.switchService('silent-hours', 'Silent Hours', this.config.showSilentSwitch === true,
|
|
60
61
|
s => s.silent.enabled, value => this.silent(value));
|
|
@@ -66,6 +67,8 @@ class FanAccessory {
|
|
|
66
67
|
const existing = this.accessory.getServiceById(S.Switch, id);
|
|
67
68
|
if (!show) { if (existing) this.accessory.removeService(existing); return null; }
|
|
68
69
|
const service = existing || this.accessory.addService(new S.Switch(this.accessory.displayName + ' ' + label, id));
|
|
70
|
+
service.displayName = this.accessory.displayName + ' ' + label;
|
|
71
|
+
service.setCharacteristic(C.Name, service.displayName);
|
|
69
72
|
if (!service.testCharacteristic(C.ConfiguredName)) service.addCharacteristic(C.ConfiguredName);
|
|
70
73
|
service.setCharacteristic(C.ConfiguredName, label);
|
|
71
74
|
this.characteristic(service, C.On, get, value => { check(typeof value === 'boolean', 'INVALID_COMMAND'); return set(value); });
|
|
@@ -121,7 +124,8 @@ class FanAccessory {
|
|
|
121
124
|
catch (error) { if (publicError(error) !== 'COMMAND_SUPERSEDED') this.fail(error); throw this.hapError(); }
|
|
122
125
|
}
|
|
123
126
|
async manual(kind, on, rpm) {
|
|
124
|
-
check(['boost', 'pause'].includes(kind) && typeof on === 'boolean'
|
|
127
|
+
check(['boost', 'pause', 'automatic'].includes(kind) && typeof on === 'boolean' &&
|
|
128
|
+
(kind !== 'automatic' || (on === false && rpm === undefined)), 'INVALID_COMMAND');
|
|
125
129
|
// Replacing the object invalidates any older queued attempt before its write.
|
|
126
130
|
clearTimeout(this.intentTimer); this.intentTimer = null;
|
|
127
131
|
const intent = { kind, on, rpm, attempted: false };
|
|
@@ -171,8 +175,9 @@ class FanAccessory {
|
|
|
171
175
|
const mode = bytes(await io.read('mode'), 1)[0];
|
|
172
176
|
check(mode === 0, 'CONTROL_REQUIRES_MULTIMODE');
|
|
173
177
|
const current = decodeManual(await io.read('manual'));
|
|
174
|
-
//
|
|
175
|
-
|
|
178
|
+
// Fan On clears either override. Individual switch-off still affects
|
|
179
|
+
// only its own kind, so a delayed Boost-off cannot cancel Pause.
|
|
180
|
+
if (!on && (kind === 'automatic' ? current.state === 'automatic' : current.state !== kind)) return this.snapshot(io);
|
|
176
181
|
const seconds = (kind === 'pause' ? this.config.pauseMinutes || 10 : this.config.boostMinutes || 10) * 60;
|
|
177
182
|
const target = kind === 'pause' ? 0 : Math.min(this.fan.maxManualRpm || MAX_RPM, rpm || this.config.boostRpm || 2000);
|
|
178
183
|
const value = on ? encodeManual(target, seconds) : Buffer.alloc(5);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-pax-calima",
|
|
3
3
|
"displayName": "SvaraHome",
|
|
4
|
-
"version": "2.5.0
|
|
4
|
+
"version": "2.5.0",
|
|
5
5
|
"description": "SvaraHome brings timed Boost, Pause and local Bluetooth control for Pax Calima and Vent-Axia Svara fans into Apple Home.",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"keywords": [
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"url": "git+https://github.com/KernowekConsulting/homebridge-pax-calima.git"
|
|
29
29
|
},
|
|
30
30
|
"bugs": {
|
|
31
|
-
"url": "https://homebridge
|
|
31
|
+
"url": "https://github.com/KernowekConsulting/homebridge-pax-calima/issues"
|
|
32
32
|
},
|
|
33
33
|
"license": "Apache-2.0",
|
|
34
34
|
"scripts": {
|
|
@@ -54,7 +54,10 @@
|
|
|
54
54
|
"docs/VALIDATION.md",
|
|
55
55
|
"docs/VERIFICATION.md",
|
|
56
56
|
"docs/DEPENDENCY-SECURITY.md",
|
|
57
|
-
"scripts/check-native.cjs"
|
|
57
|
+
"scripts/check-native.cjs",
|
|
58
|
+
"docs/BETA1-LIVE-DIAGNOSTIC.md",
|
|
59
|
+
"docs/pi-live-control-evidence-20261025.jsonl",
|
|
60
|
+
"docs/STABLE-PROMOTION.md"
|
|
58
61
|
],
|
|
59
62
|
"dependencies": {
|
|
60
63
|
"@stoprocent/noble": "2.8.0"
|