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 CHANGED
@@ -1,91 +1,16 @@
1
1
  # Changelog
2
2
 
3
- [Release notes](RELEASE_NOTES.md) describe the proposed update. Beta entries are consolidated into the stable release when it is promoted; beta history remains in GitHub prereleases and tags.
4
-
5
- ## 2.5.0-beta.2 — Patient requests, truthful tiles
6
-
7
- - Keep Boost, Pause and speed requests pending through temporary Bluetooth failures, including child-bridge restarts. A newer manual command replaces the pending request.
8
- - Confirm the fan's state before showing an action as active. Check uncertain writes before retrying, preserving an already-running timer.
9
- - Restore measured speed after HomeKit caches a requested slider position.
10
- - Retry stalled disconnects and wait for scanning to stop before connecting.
11
- - Allow a short authentication processing interval before protected controls and log differing manual readback without exposing PINs.
12
- - Retain a recent verified reading during a missed background poll, within the existing 45-second freshness limit.
13
- - Add explicit Boost/Pause tile names and identify the fan in communication logs.
14
- - Add an optional speed-target limit for each fan, covering Boost and the Home speed slider. This accommodates the owner's older Wetroom fan, which accepts 2400 RPM and returns zero RPM for a 2450 RPM request, while retaining Kitchen's existing setting.
15
- - Stop retries for rejected authentication, invalid data, explicitly different control readback or unsupported operating modes. Siri can still time out before Bluetooth recovers; a pending request continues until confirmed, replaced or stopped by one of these faults.
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 in Apple Home. No cloud account is needed.
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
- [Visit SvaraHome for setup guidance and support](https://homebridge.svarahome.kernowekconsulting.co.uk).
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
- ## Set up your fan
11
+ **SvaraHome 2.5.0** brings timed Boost, Pause and confirmed fan feedback to Apple Home.
10
12
 
11
- Install `homebridge-pax-calima` through Homebridge UI, then open Plugin Config. Add each fan's Bluetooth address and its own six- or eight-digit PIN from the official app. Keep leading zeroes. Close the official app while Homebridge connects.
13
+ ## What you get in Apple Home
12
14
 
13
- Use Node 22.12 or later within Node 22, or Node 24, with Homebridge 1.8+ or 2. A working Bluetooth adapter and the normal Bluetooth access for your Homebridge installation are required. A dedicated child bridge is recommended. This plugin does not alter system permissions or install system tools.
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
- ```json
16
- {
17
- "platform": "PaxCalima",
18
- "name": "SvaraHome",
19
- "fans": [
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
- The address and PIN above are examples. Each fan needs its own entry. An empty or invalid configuration does not start Bluetooth discovery. Incorrect fan entries are skipped, with a short explanation in the Homebridge log. There is no fallback PIN or automatic pairing with nearby fans.
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
- ## In Apple Home
30
+ ## Use your own words
31
31
 
32
- **Boost** runs the fan at your chosen speed for the configured time. Turn it off to return to automatic ventilation. Turn it on again to start a fresh full duration.
32
+ Assign each fan to its room in Apple Home. In a room named Kitchen, try:
33
33
 
34
- **Pause** stops the fan temporarily. The fan's own timer returns it to automatic ventilation, even if Homebridge disconnects. Turn Pause off to resume sooner. The motor can take several seconds to respond.
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
- Boost and Pause share one manual override: starting one replaces the other. Switching off an already inactive control leaves the other action alone. The switches follow the fan's readback, including actions started in the official app; updates arrive after a successful poll, normally around every ten seconds plus Bluetooth connection time. Home does not show a remaining-time countdown.
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
- Name the switches clearly in Home, such as Kitchen Boost and Kitchen Pause. You can then use scenes or Siri phrases such as “Turn on Kitchen Boost” and “Turn on Kitchen Pause”. Siri wording and tile grouping depend on your Home setup; a custom scene can provide your preferred phrase.
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
- The fan's speed slider starts a temporary manual session using the Boost duration. Nonzero targets range from 1000 to 2500 RPM in steps of 25; percentages below 40% request the minimum 1000 RPM. Zero starts Pause. The displayed percentage follows measured RPM, so it can differ while the motor settles. Turning the fan off starts a timed Pause; turning it on clears an active Pause and returns to automatic ventilation. Automatic mode may still leave the motor idle under its native rules.
42
+ ## Get started
41
43
 
42
- Each fan can have its own **Maximum requested speed** in Plugin Config (`maxManualRpm`). This caps both Boost and speed-slider targets for that fan while keeping the displayed speed tied to measurement. Leave it blank for the normal 2500 RPM target limit. The owner's older Wetroom fan accepted 2400 RPM but returned zero RPM for a 2450 RPM request; its validated limit is therefore set to 2400. This observation does not establish the limit for every fan with that firmware.
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
- After saving configuration changes, use **Restart Child Bridge** on SvaraHome's plugin card. During validation, terminating the child process directly reloaded its source but retained the parent's previous configuration; the Homebridge UI restart applied the saved fan limit.
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
- Hide either switch in Plugin Config if you prefer fewer tiles. Hiding a switch does not cancel a running action. Temporary controls currently require operating mode 00, the mode tested on the newer Kitchen fan. The plugin refuses controls in other modes and does not change installation modes.
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
- ## Quiet hours
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
- Leave both time fields blank to retain the fan's own schedule. To save a new schedule, enter different start and end times in 24-hour format. A changed plugin schedule is applied and checked once. Later changes in the official app are retained across polls and Homebridge restarts.
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
- The optional Silent Hours switch enables or disables that saved schedule while preserving its times. It does not start an immediate quiet period; use Pause for that. Native quiet-hours suppression of automatic boosts has not yet been behaviorally verified by this project.
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
- ## Upgrading from 2.4.x
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
- - Retain the existing fan accessory and its Home assignment. Correct each fan's address/PIN in Plugin Config; name-only entries cannot be routed safely.
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
- ## When a fan is unavailable
97
+ ## If a fan is unavailable
64
98
 
65
- Boost, Pause and speed requests remain pending through temporary Bluetooth failures. SvaraHome retries every ten seconds after a failed attempt until readback confirms the request or a newer manual command replaces it. Pending requests survive child-bridge restarts. To cancel a pending Boost, turn Boost off; to cancel a pending Pause, turn Pause off. A request may therefore run when the fan becomes reachable later.
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
- The tiles follow verified fan state, never the pending request. If a reply is lost after a write, a retry first checks whether the requested override is already running, avoiding repeated timer extensions. Siri or HomeKit can time out before recovery; an error from Siri does not cancel the pending request or prove the fan did not receive it. Homebridge logs identify pending requests.
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
- A missed background poll retains the last verified reading only within the existing 45-second freshness limit. Home reports a communication failure when authentication fails, a command fails, telemetry is stale or RPM is outside the accepted range. Rejected authentication, invalid data, an explicitly different control readback and unsupported operating modes stop command retries and need attention. A rejected PIN also stops unattended authentication retries; correct the configuration and restart the child bridge, then issue the request again.
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
- Check the fan's address and PIN securely in Plugin Config, Bluetooth range and adapter access, and whether another app is connected. The plugin never prints PINs or raw backend errors. After a timed-out disconnect, it retries disconnection before allowing another session to use the radio. It waits for scanning to stop before connecting. Persistent adapter failures may still require attention.
105
+ ## Upgrading to 2.5
72
106
 
73
- ## What has been checked
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
- Device-level trials on the owner's newer eight-digit-PIN Kitchen fan established timed Boost, timed zero-RPM Pause, expiry, early resume and speed changes. All tested settings were restored. Both Kitchen and the older Wetroom fan subsequently authenticated and provided telemetry after Wetroom's address and PIN were corrected. Kitchen's pending-command retries were also exercised through HomeKit switches. Wetroom's firmware 02.08 accepted a temporary 2400 RPM Boost, confirmed by HomeKit readback, and returned to automatic ventilation after cancellation. Its initial 2450 RPM request produced a zero-RPM override; the per-fan target limit addresses this observed difference.
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
- Version 2.5.0-beta.2 adds recovery and pending-command fixes to beta.1. The control implementation has been tested on the owner's Pi, with automated protocol, queue and native Homebridge-service checks. See [live diagnostic evidence](docs/BETA1-LIVE-DIAGNOSTIC.md), [validation](docs/VALIDATION.md), [release notes](RELEASE_NOTES.md) and [changelog](CHANGELOG.md). Brief successful sessions do not establish sustained Bluetooth reliability.
111
+ ## About the project
78
112
 
79
- Homebridge verification remains an aim. The SvaraHome logo is bundled for the icon request; Homebridge controls verified status and icon display. See [verification preparation](docs/VERIFICATION.md).
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
- Dependency security: this candidate uses the maintained Noble library. The recorded six high and one critical dependency findings have been removed; fresh audits report zero vulnerabilities. See [security evidence](docs/DEPENDENCY-SECURITY.md).
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-beta.2 — Patient requests, truthful tiles
1
+ # SvaraHome 2.5.0 — Your fan, at home
2
2
 
3
- Ask for a boost. Let SvaraHome work through a temporary Bluetooth interruption. See what the fan has confirmed.
3
+ A boost when you need it. A quiet moment when you want one. An easy way back to normal.
4
4
 
5
- This beta builds on SvaraHome's timed Boost and Pause controls, with recovery improvements tested on both the newer Kitchen fan and the older Wetroom fan.
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
- ## A request worth waiting for
7
+ ## Familiar controls
8
8
 
9
- Boost, Pause and speed requests now stay pending through temporary Bluetooth failures. SvaraHome retries after a failed attempt, including after a child-bridge restart. A newer manual command replaces the waiting request.
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
- For example, say, “Siri, boost the kitchen fan.” Siri may still time out while Bluetooth recovers; the request can continue afterwards. Turn Boost off to cancel a pending Boost, or Pause off to cancel a pending Pause. A waiting request can start when the fan becomes reachable later.
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
- Rejected authentication, invalid data, unsupported operating modes and an explicitly different control readback stop retries and need attention.
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
- ## What Home shows
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
- Boost and Pause follow the fan's confirmed manual state. The speed slider returns to measured speed after a request, rather than staying at the percentage you asked for.
17
+ ## Clearer feedback, less maintenance
18
18
 
19
- An uncertain write is checked before it is repeated, so an already-running timer is preserved. A missed background poll retains the last verified reading only within the existing 45-second freshness limit. Failed commands and stale or invalid readings report a communication fault.
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 recovery now retries stalled disconnects and waits for scanning to stop before connecting. Logs identify which fan needs attention, and Boost and Pause have explicit tile names.
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
- ## A limit for each fan
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
- Check that each fan has its own Bluetooth address and correct six- or eight-digit PIN. Close the official app while Homebridge connects. After saving configuration changes, use **Restart Child Bridge** on SvaraHome's plugin card so the saved settings are loaded.
32
-
33
- Timed controls keep the fan's own expiry timer and leave persistent ventilation presets in place. Existing fan identities and room assignments are retained. If upgrading from 2.4.x, check scenes that used the old Boost event button; it is replaced by a working switch. Unsupported temperature, humidity and light tiles are removed.
34
-
35
- Setup guidance and support now live at the [SvaraHome website](https://homebridge.svarahome.kernowekconsulting.co.uk).
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
- This is a testing release. Homebridge verification remains pending.
33
+ Setup guidance and support are at the [SvaraHome website](https://homebridge.svarahome.kernowekconsulting.co.uk).
@@ -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’s six- or eight-digit PIN, including any leading zeroes. The PIN is stored in your Homebridge configuration.",
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. Turning Boost off returns the fan to automatic ventilation."
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": true,
80
- "description": "Stop the fan temporarily. Ventilation returns automatically when the fan’s timer ends. Turn Pause off to resume sooner."
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’s existing schedule."
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’s saved quiet-hours schedule. This preserves its times; it does not start an immediate pause."
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": "Boost and Pause",
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.
@@ -1,61 +1,35 @@
1
- # 2.5.0-beta.2 validation
1
+ # SvaraHome 2.5 validation
2
2
 
3
- The control implementation (revision 9f30bae) passed all 48 tests in each Node 22/24 and Homebridge 1/2 combination in [Linux CI run 40195658845](https://github.com/KernowekConsulting/homebridge-pax-calima/actions/runs/40195658845). Live HAP checks confirmed Boost, Pause and cancellation on Kitchen and Wetroom, plus Wetroom slider control with its 2400 RPM target ceiling. Both fans finished with manual overrides Off and no pending requests.
3
+ ## Current code evidence
4
4
 
5
- See [detailed live evidence](BETA1-LIVE-DIAGNOSTIC.md) and [42 redacted final-trial records](pi-live-control-evidence-20261025.jsonl) in the repository. The beta.2 release preparation changes version metadata, website/support links and release documentation; its runtime control files are unchanged from the tested revision. Publication status must be confirmed separately against npm and GitHub.
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
- The following records describe the original beta.1 validation, including acceptance gates that were outstanding at that time. The later live evidence above supersedes those historical gaps. Siri voice interaction and sustained Bluetooth reliability are not established by HAP control trials.
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
- ## Historical beta.1 candidate validation
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
- 25 October 2026. Base commit: `1f22f3ab8136cf1ea5f13ea736a6722f4bfdd2b0` (2.4.5). Work is on local branch `feat/2.5.0-boost-pause`. No Pi plugin deployment, service stop, firmware update, reset or new fan-setting write was performed during implementation.
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
- ## Automated checks
15
+ ## Physical evidence
15
16
 
16
- 32 tests pass in each combination:
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
- | Node | Homebridge | Result |
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
- Machine-readable results and complete TAP logs are alongside this file in the source checkout; those raw QA files are excluded from the npm package. Tests instantiate the real Homebridge PlatformAccessory and HAP service classes, and the maintained Noble library’s real classes, with simulated physical Bluetooth bindings. They do not start a real Homebridge server, pair an iPhone or connect to a fan.
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
- Coverage includes explicit PIN encoding/confirmation, authentication rejection, queue ordering, failed command readback, scan/ATT timeouts and cleanup, late connection recovery, shutdown, stale and malformed telemetry, native service handlers, restart reconciliation, modes, upgrades, visibility, schedules and config routing. Overlapping poll/Boost/Pause requests all execute serially. Rejected authentication stops unattended retries; an explicit user command or configuration restart can retry.
23
+ ## Remaining acceptance and practical limits
28
24
 
29
- `test/telemetry-fixture.json` replays 134 redacted status/manual samples from the owner's serial Kitchen tests. Three samples contain two implausible RPM values, 13140 and 50237 (the latter occurs twice). All three are rejected. Disabled manual buffers retaining an old target are treated as automatic, rather than active Boost. Firmware-mode and RPM controls retain the documented conservative gates.
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
- Source syntax, diff whitespace and npm package contents are checked separately. The package includes runtime modules, schema, logo, README, release notes, changelog and licence; test recordings and diagnostic scripts are excluded. The packaged README links the repository documentation for validation details.
33
+ ## Historical records
32
34
 
33
- ## Physical evidence reused
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.
@@ -1,47 +1,53 @@
1
- # Homebridge verification preparation
1
+ # Homebridge verification readiness
2
2
 
3
- Reviewed 25 October 2026. This is preparation for a request, not a claim of approval.
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
- ## Current sources
5
+ ## Assessment
6
6
 
7
- - [Homebridge](https://homebridge.io/)
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
- The current requirements name supported Node LTS 22 and 24, a dynamic platform, settings GUI, graceful errors, explicit configuration before startup, no tracking, and Homebridge-local storage. A published npm package, public GitHub source with issues enabled, and matching GitHub release notes are required. Current UI transport metadata supports `supports-hap`, which this package declares. It does not register Matter accessories itself.
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
- ## Assessment
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
- | Area | Candidate evidence / remaining work |
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
- ## Supplied icon
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
- SvaraHome’s layered blue house-and-fan artwork is retained in `assets/svarahome-master.png`, with a 1024-pixel version in `assets/svarahome.png`. The square 100 × 100 PNG `assets/homebridge-pax-calima.png` matches the form's requested approximate size and format. Its text and blue background were visually checked at that size.
37
+ ## Remaining work before requesting review
33
38
 
34
- The verification form can include an icon. The separate icon request form requires the plugin to be verified first and the requester to be its developer. Homebridge then registers the icon centrally; adding a logo URL to package metadata alone does not enable the tile. No invented metadata field or verified badge has been added.
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
- Prepared request details:
45
+ ## Logo
37
46
 
38
- - npm name: `homebridge-pax-calima`
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
- ## Release writing
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
- Tone references: GivHome [4.1.0](https://github.com/KernowekConsulting/homebridge-giv-iog-local/releases/tag/v4.1.0), [4.1.1 changelog](https://github.com/KernowekConsulting/homebridge-giv-iog-local/blob/v4.1.1/CHANGELOG.md) and recent prereleases. The default-branch changelog currently describes stable v3, so the v4 tag was used for the recent stable style.
51
+ ## Stable release preparation — 26 October 2026
46
52
 
47
- Lead with everyday intent and outcomes, explain what a tile does in plain language, state defaults and continuity, then separate tested behavior from future aims. Avoid claims of verification or complete compatibility while the relevant checks remain open. Drafts are in RELEASE_NOTES.md and CHANGELOG.md.
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('pause', false); });
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 !== false,
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', 'INVALID_COMMAND');
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
- // Stale switch-off must not cancel a newer override of another kind.
175
- if (!on && current.state !== kind) return this.snapshot(io);
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-beta.2",
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.svarahome.kernowekconsulting.co.uk"
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"