homebridge-pax-calima 2.4.3 → 2.4.5

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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  If you have a **Pax Calima** or **Vent-Axia Lo-Carbon Svara** extractor fan, this plugin connects it directly to HomeKit via Bluetooth. Once set up, your fan appears in the Home app with live temperature and fan speed — and you can build automations around all of them.
6
6
 
7
- [![Homebridge 2.0 Ready](https://img.shields.io/badge/Homebridge-2.0%20Ready-brightgreen)](https://github.com/homebridge/homebridge/wiki/Updating-To-Homebridge-v2.0)
7
+ [![Homebridge 2 Ready](https://img.shields.io/badge/Homebridge-2%20Ready-brightgreen)](https://github.com/homebridge/homebridge/wiki/Updating-To-Homebridge-v2.0)
8
8
  [![npm](https://img.shields.io/npm/v/homebridge-pax-calima)](https://www.npmjs.com/package/homebridge-pax-calima)
9
9
 
10
10
  ---
@@ -178,20 +178,30 @@ Go to Homebridge UI → plugin settings → Remove Accessory Cache, then restart
178
178
 
179
179
  ---
180
180
 
181
- ## Homebridge 2.0 compliance
181
+ ## Homebridge 2 compatibility
182
182
 
183
- This plugin meets all Homebridge 2.0 requirements:
183
+ This plugin is compatible with Homebridge 2:
184
184
  - Registered as a dynamic platform
185
- - Waits for `didFinishLaunching` before any BLE or accessory work
186
- - All errors caught and logged — no unhandled exceptions
185
+ - Waits for `didFinishLaunching` before starting BLE or accessory work
186
+ - Uses the Homebridge 2-compatible `Accessory.getServiceById()` API for the optional Silent Hours service
187
187
  - No analytics, tracking or post-install scripts
188
- - Accessories restored from cache cleanly without re-registration
189
- - Compatible with Node.js 18, 20 and 22
188
+ - Accessories restore cleanly from cache without re-registration
189
+ - Requires Node.js 18.20.4 or later
190
+ - Live-tested on Homebridge 2.4.0 (HAP 2.2.2) with Node.js 24.19.0
190
191
 
191
192
  ---
192
193
 
193
194
  ## Release notes
194
195
 
196
+ ### 2.4.5
197
+ - **Fixed:** Homebridge 2 compatibility for the optional Silent Hours switch. Homebridge 2 removed `Accessory.getServiceByUUIDAndSubType()`; both lookups now use the supported `Accessory.getServiceById()` API.
198
+ - **Verified:** Live-tested successfully on Homebridge 2.4.0 (HAP 2.2.2) with Node.js 24.19.0 on Homebridge OS.
199
+ - No BLE protocol, fan control, sensor mapping, configuration, or accessory behaviour changes.
200
+
201
+ ### 2.4.4
202
+ - **Fixed:** Silent Hours time fields no longer show a raw regex pattern as validation hint in the Homebridge UI — replaced with plain human-readable placeholder text (e.g. `23:00`) and a description
203
+ - **Improved:** Invalid time format now logs a clear warning message rather than silently disabling the schedule
204
+
195
205
  ### 2.4.3
196
206
  - **Silent Hours** reworked — now supports a config schedule (`silentHoursStart` / `silentHoursEnd`) that runs automatically, an optional HomeKit switch (`showSilentSwitch: true`) for Goodnight scenes and irregular schedules, or both together. The switch takes priority when toggled manually; the schedule runs as a background default. Any existing Silent Hours switch from earlier versions is automatically removed unless `showSilentSwitch` is enabled.
197
207
  - **Light sensor** (`showLight`) added as opt-in — confirmed via live testing that the characteristic returns a static value regardless of lighting conditions.
@@ -13,22 +13,20 @@
13
13
  "silentHoursStart": {
14
14
  "title": "Silent Hours — Start Time",
15
15
  "type": "string",
16
- "pattern": "^([01]?[0-9]|2[0-3]):[0-5][0-9]$",
17
- "placeholder": "e.g. 23:00",
18
- "description": "When the fan stops boosting at night. 24-hour format. Leave blank to disable the schedule."
16
+ "placeholder": "23:00",
17
+ "description": "When the fan stops boosting at night. Enter in 24-hour format, e.g. 23:00. Leave blank to disable the schedule."
19
18
  },
20
19
  "silentHoursEnd": {
21
20
  "title": "Silent Hours — End Time",
22
21
  "type": "string",
23
- "pattern": "^([01]?[0-9]|2[0-3]):[0-5][0-9]$",
24
- "placeholder": "e.g. 07:00",
25
- "description": "When the fan resumes boosting in the morning. Both start and end must be set for the schedule to activate."
22
+ "placeholder": "07:00",
23
+ "description": "When the fan resumes boosting in the morning. Enter in 24-hour format, e.g. 07:00. Both start and end must be set for the schedule to activate."
26
24
  },
27
25
  "showSilentSwitch": {
28
26
  "title": "Show Silent Hours Switch in Home",
29
27
  "type": "boolean",
30
28
  "default": false,
31
- "description": "Adds a Silent Hours on/off switch to your accessory in the Home app. Useful for including in a Goodnight scene or automation. If a schedule is also set, the switch takes priority when toggled manually. Good for shift workers or irregular schedules."
29
+ "description": "Adds a Silent Hours on/off switch to your accessory in the Home app. Useful for including in a Goodnight scene or automation. Good for shift workers or irregular schedules."
32
30
  },
33
31
  "showHumidity": {
34
32
  "title": "Show Humidity Sensor",
@@ -57,8 +55,8 @@
57
55
  "mac": {
58
56
  "title": "MAC Address",
59
57
  "type": "string",
60
- "pattern": "^([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})$",
61
- "description": "MAC address of the fan (e.g. 58:2b:db:xx:xx:xx)"
58
+ "placeholder": "58:2b:db:xx:xx:xx",
59
+ "description": "MAC address of the fan — found in the official Pax or Vent-Axia app under About Device."
62
60
  },
63
61
  "pin": {
64
62
  "title": "PIN Code",
package/index.js CHANGED
@@ -15,13 +15,19 @@ const MAC_PREFIX = '58:2b:db';
15
15
  const POLL_MS = 10000;
16
16
  const RECONNECT_MS = 15000;
17
17
 
18
- function parseTime(str) {
18
+ function parseTime(str, label) {
19
19
  if (!str || typeof str !== 'string') return null;
20
20
  const parts = str.split(':');
21
- if (parts.length !== 2) return null;
21
+ if (parts.length !== 2 || parts[0] === '' || parts[1] === '') {
22
+ console.warn('[PaxCalima] ' + (label || 'Silent Hours') + ' time "' + str + '" is not valid — use 24-hour format e.g. 23:00. Silent Hours schedule disabled.');
23
+ return null;
24
+ }
22
25
  const hour = parseInt(parts[0], 10);
23
26
  const minute = parseInt(parts[1], 10);
24
- if (isNaN(hour) || isNaN(minute) || hour < 0 || hour > 23 || minute < 0 || minute > 59) return null;
27
+ if (isNaN(hour) || isNaN(minute) || hour < 0 || hour > 23 || minute < 0 || minute > 59) {
28
+ console.warn('[PaxCalima] ' + (label || 'Silent Hours') + ' time "' + str + '" is out of range — use 24-hour format e.g. 23:00. Silent Hours schedule disabled.');
29
+ return null;
30
+ }
25
31
  return { hour, minute };
26
32
  }
27
33
 
@@ -124,8 +130,8 @@ class PaxCalimaAccessory {
124
130
  this.showHumidity = options.showHumidity || false;
125
131
  this.showLight = options.showLight || false;
126
132
  this.showSilentSwitch = options.showSilentSwitch || false;
127
- this.silentStart = parseTime(options.silentHoursStart);
128
- this.silentEnd = parseTime(options.silentHoursEnd);
133
+ this.silentStart = parseTime(options.silentHoursStart, 'silentHoursStart');
134
+ this.silentEnd = parseTime(options.silentHoursEnd, 'silentHoursEnd');
129
135
 
130
136
  this.currentRPM = 0;
131
137
  this.humidity = 0;
@@ -169,7 +175,7 @@ class PaxCalimaAccessory {
169
175
  // Silent Hours switch — opt-in via showSilentSwitch: true
170
176
  // Coexists with config schedule — switch state takes priority on next poll
171
177
  if (this.showSilentSwitch) {
172
- this.silentService = this.accessory.getServiceByUUIDAndSubType(Service.Switch, 'silent-hours')
178
+ this.silentService = this.accessory.getServiceById(Service.Switch, 'silent-hours')
173
179
  || this.accessory.addService(new Service.Switch(n + ' Silent Hours', 'silent-hours'));
174
180
  this.silentService.getCharacteristic(Characteristic.On)
175
181
  .onGet(() => this.silentHours)
@@ -180,7 +186,7 @@ class PaxCalimaAccessory {
180
186
  this.log.info('Silent Hours switch enabled');
181
187
  } else {
182
188
  // Remove switch if it was registered in a previous version
183
- const existing = this.accessory.getServiceByUUIDAndSubType(Service.Switch, 'silent-hours');
189
+ const existing = this.accessory.getServiceById(Service.Switch, 'silent-hours');
184
190
  if (existing) {
185
191
  this.accessory.removeService(existing);
186
192
  this.log.info('Silent Hours switch removed — use config schedule or enable showSilentSwitch');
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "homebridge-pax-calima",
3
3
  "displayName": "Vent-Axia Svara / Pax Calima",
4
- "version": "2.4.3",
5
- "description": "Bring your Pax Calima or Vent-Axia Svara bathroom fan into Apple Home via Bluetooth — live temperature and fan speed with Silent Hours scheduling and full automation support.",
4
+ "version": "2.4.5",
5
+ "description": "Bring your Pax Calima or Vent-Axia Svara bathroom fan into Apple Home via Bluetooth \u2014 live temperature and fan speed with Silent Hours scheduling and full automation support.",
6
6
  "main": "index.js",
7
7
  "keywords": [
8
8
  "homebridge-plugin",