homebridge-bedjet 0.3.2 → 0.3.4

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/dist/accessory.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BedJetAccessory = void 0;
4
4
  const BedJet_1 = require("./bedjet/BedJet");
5
5
  const constants_1 = require("./bedjet/constants");
6
+ const utils_1 = require("./utils");
6
7
  const DEFAULT_MODE_MAP = {
7
8
  heat: constants_1.OperatingMode.HEAT,
8
9
  turbo: constants_1.OperatingMode.TURBO,
@@ -10,20 +11,6 @@ const DEFAULT_MODE_MAP = {
10
11
  cool: constants_1.OperatingMode.COOL,
11
12
  dry: constants_1.OperatingMode.DRY,
12
13
  };
13
- /**
14
- * HomeKit only allows alphanumeric, space, and apostrophe characters in names,
15
- * starting and ending with alphanumeric. Underscores and other punctuation
16
- * cause HAP warnings and may prevent the accessory from pairing.
17
- */
18
- function sanitizeName(name) {
19
- return name
20
- .replace(/_/g, ' ') // underscores → spaces
21
- .replace(/[^a-zA-Z0-9 ']/g, ' ') // anything else invalid → space
22
- .replace(/\s+/g, ' ') // collapse multiple spaces
23
- .trim()
24
- .replace(/^[^a-zA-Z0-9]+/, '') // must start with alphanumeric
25
- .replace(/[^a-zA-Z0-9]+$/, '') || 'BedJet'; // must end with alphanumeric
26
- }
27
14
  // OperatingMode → CurrentHeatingCoolingState value
28
15
  const CURRENT_STATE_MAP = {
29
16
  [constants_1.OperatingMode.STANDBY]: 0, // OFF
@@ -66,7 +53,7 @@ class BedJetAccessory {
66
53
  this.pendingMode = null;
67
54
  this.pendingModeTimer = null;
68
55
  const { Service, Characteristic } = platform.api.hap;
69
- const safeName = sanitizeName(config.name);
56
+ const safeName = (0, utils_1.sanitizeName)(config.name);
70
57
  // AccessoryInformation
71
58
  const infoService = this.accessory.getService(Service.AccessoryInformation)
72
59
  ?? this.accessory.addService(Service.AccessoryInformation);
@@ -105,13 +92,22 @@ class BedJetAccessory {
105
92
  return 1; // HEAT / TURBO / EXTENDED_HEAT
106
93
  })
107
94
  .onSet((value) => {
108
- this.setPending(value, 'pendingMode', 'pendingModeTimer');
95
+ const val = value;
109
96
  const wasOff = this.bedjet.state.operatingMode === constants_1.OperatingMode.STANDBY
110
97
  || this.bedjet.state.operatingMode === constants_1.OperatingMode.WAIT;
111
- const turningOn = value !== 0;
112
- const mode = TARGET_TO_MODE[value] ?? constants_1.OperatingMode.STANDBY;
113
- // Apply the requested mode, then defaults (temp/fan) if turning on from off
114
- this._applyModeAndDefaults(mode, wasOff && turningOn, false).catch(err => this.platform.log.error(`[${config.name}] setOperatingMode failed: ${err}`));
98
+ const turningOn = val !== 0;
99
+ let mode;
100
+ if (val === 3 || (turningOn && wasOff)) {
101
+ // Siri sends Auto (3) when turning on and any turn-on from standby —
102
+ // should respect the user's configured defaultMode.
103
+ mode = config.defaultMode
104
+ ? DEFAULT_MODE_MAP[config.defaultMode]
105
+ : TARGET_TO_MODE[val] ?? constants_1.OperatingMode.HEAT;
106
+ }
107
+ else {
108
+ mode = TARGET_TO_MODE[val] ?? constants_1.OperatingMode.STANDBY;
109
+ }
110
+ this._applyModeAndDefaults(mode, wasOff && turningOn).catch(err => this.platform.log.error(`[${config.name}] setOperatingMode failed: ${err}`));
115
111
  });
116
112
  // FanV2 service
117
113
  this.fanService = this.accessory.getService(Service.Fanv2)
@@ -130,7 +126,7 @@ class BedJetAccessory {
130
126
  const mode = this.config.defaultMode
131
127
  ? DEFAULT_MODE_MAP[this.config.defaultMode]
132
128
  : constants_1.OperatingMode.HEAT;
133
- this._applyModeAndDefaults(mode, true, true).catch(err => this.platform.log.error(`[${config.name}] turn on failed: ${err}`));
129
+ this._applyModeAndDefaults(mode, true).catch(err => this.platform.log.error(`[${config.name}] turn on failed: ${err}`));
134
130
  }
135
131
  });
136
132
  this.fanService.getCharacteristic(Characteristic.RotationSpeed)
@@ -165,7 +161,7 @@ class BedJetAccessory {
165
161
  * (fan turn-on path); false when HomeKit supplied the mode explicitly
166
162
  * (thermostat path).
167
163
  */
168
- async _applyModeAndDefaults(mode, applyDefaults, applyMode) {
164
+ async _applyModeAndDefaults(mode, applyDefaults) {
169
165
  const { config } = this;
170
166
  // Determine HomeKit target state for pending optimistic value
171
167
  const pendingState = mode === constants_1.OperatingMode.STANDBY ? 0
package/dist/platform.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BedJetPlatform = exports.PLUGIN_NAME = exports.PLATFORM_NAME = void 0;
4
4
  const accessory_1 = require("./accessory");
5
+ const utils_1 = require("./utils");
5
6
  exports.PLATFORM_NAME = 'BedJetPlatform';
6
7
  exports.PLUGIN_NAME = 'homebridge-bedjet';
7
8
  class BedJetPlatform {
@@ -35,15 +36,18 @@ class BedJetPlatform {
35
36
  const uuid = this.api.hap.uuid.generate(device.address.toLowerCase());
36
37
  this.discoveredUUIDs.push(uuid);
37
38
  const existing = this.accessories.get(uuid);
39
+ const safeName = (0, utils_1.sanitizeName)(device.name);
38
40
  if (existing) {
39
41
  this.log.info('Restoring existing accessory from cache:', existing.displayName);
40
42
  existing.context.device = device;
43
+ // Update the display name in case the config name changed or was invalid
44
+ existing.displayName = safeName;
41
45
  this.api.updatePlatformAccessories([existing]);
42
46
  new accessory_1.BedJetAccessory(this, existing, device);
43
47
  }
44
48
  else {
45
- this.log.info('Adding new accessory:', device.name);
46
- const accessory = new this.api.platformAccessory(device.name, uuid);
49
+ this.log.info('Adding new accessory:', safeName);
50
+ const accessory = new this.api.platformAccessory(safeName, uuid);
47
51
  accessory.context.device = device;
48
52
  new accessory_1.BedJetAccessory(this, accessory, device);
49
53
  this.api.registerPlatformAccessories(exports.PLUGIN_NAME, exports.PLATFORM_NAME, [accessory]);
@@ -0,0 +1,7 @@
1
+ /**
2
+ * HomeKit only allows alphanumeric, space, and apostrophe characters in
3
+ * accessory/service names, starting and ending with an alphanumeric character.
4
+ * Underscores and other punctuation cause HAP warnings and may prevent the
5
+ * accessory from being added to the Home app.
6
+ */
7
+ export declare function sanitizeName(name: string): string;
package/dist/utils.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeName = sanitizeName;
4
+ /**
5
+ * HomeKit only allows alphanumeric, space, and apostrophe characters in
6
+ * accessory/service names, starting and ending with an alphanumeric character.
7
+ * Underscores and other punctuation cause HAP warnings and may prevent the
8
+ * accessory from being added to the Home app.
9
+ */
10
+ function sanitizeName(name) {
11
+ return name
12
+ .replace(/_/g, ' ') // underscores → spaces
13
+ .replace(/[^a-zA-Z0-9 ']/g, ' ') // other invalid chars → space
14
+ .replace(/\s+/g, ' ') // collapse runs of spaces
15
+ .trim()
16
+ .replace(/^[^a-zA-Z0-9]+/, '') // must start with alphanumeric
17
+ .replace(/[^a-zA-Z0-9]+$/, '') // must end with alphanumeric
18
+ || 'BedJet';
19
+ }
20
+ //# sourceMappingURL=utils.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "homebridge-bedjet",
3
3
  "displayName": "BedJet",
4
- "version": "0.3.2",
4
+ "version": "0.3.4",
5
5
  "description": "Homebridge plugin for BedJet V3 via Bluetooth LE",
6
6
  "license": "MIT",
7
7
  "main": "dist/index.js",
package/src/accessory.ts CHANGED
@@ -3,6 +3,7 @@ import { BedJet } from './bedjet/BedJet';
3
3
  import { OperatingMode } from './bedjet/constants';
4
4
  import type { BedJetConfig, BedJetState, DefaultMode } from './bedjet/types';
5
5
  import type { BedJetPlatform } from './platform';
6
+ import { sanitizeName } from './utils';
6
7
 
7
8
  const DEFAULT_MODE_MAP: Record<DefaultMode, OperatingMode> = {
8
9
  heat: OperatingMode.HEAT,
@@ -12,20 +13,6 @@ const DEFAULT_MODE_MAP: Record<DefaultMode, OperatingMode> = {
12
13
  dry: OperatingMode.DRY,
13
14
  };
14
15
 
15
- /**
16
- * HomeKit only allows alphanumeric, space, and apostrophe characters in names,
17
- * starting and ending with alphanumeric. Underscores and other punctuation
18
- * cause HAP warnings and may prevent the accessory from pairing.
19
- */
20
- function sanitizeName(name: string): string {
21
- return name
22
- .replace(/_/g, ' ') // underscores → spaces
23
- .replace(/[^a-zA-Z0-9 ']/g, ' ') // anything else invalid → space
24
- .replace(/\s+/g, ' ') // collapse multiple spaces
25
- .trim()
26
- .replace(/^[^a-zA-Z0-9]+/, '') // must start with alphanumeric
27
- .replace(/[^a-zA-Z0-9]+$/, '') || 'BedJet'; // must end with alphanumeric
28
- }
29
16
 
30
17
  // OperatingMode → CurrentHeatingCoolingState value
31
18
  const CURRENT_STATE_MAP: Record<OperatingMode, number> = {
@@ -130,13 +117,23 @@ export class BedJetAccessory {
130
117
  return 1; // HEAT / TURBO / EXTENDED_HEAT
131
118
  })
132
119
  .onSet((value: CharacteristicValue) => {
133
- this.setPending(value as number, 'pendingMode', 'pendingModeTimer');
120
+ const val = value as number;
134
121
  const wasOff = this.bedjet.state.operatingMode === OperatingMode.STANDBY
135
122
  || this.bedjet.state.operatingMode === OperatingMode.WAIT;
136
- const turningOn = (value as number) !== 0;
137
- const mode = TARGET_TO_MODE[value as number] ?? OperatingMode.STANDBY;
138
- // Apply the requested mode, then defaults (temp/fan) if turning on from off
139
- this._applyModeAndDefaults(mode, wasOff && turningOn, false).catch(err =>
123
+ const turningOn = val !== 0;
124
+
125
+ let mode: OperatingMode;
126
+ if (val === 3 || (turningOn && wasOff)) {
127
+ // Siri sends Auto (3) when turning on — and any turn-on from standby —
128
+ // should respect the user's configured defaultMode.
129
+ mode = config.defaultMode
130
+ ? DEFAULT_MODE_MAP[config.defaultMode]
131
+ : TARGET_TO_MODE[val] ?? OperatingMode.HEAT;
132
+ } else {
133
+ mode = TARGET_TO_MODE[val] ?? OperatingMode.STANDBY;
134
+ }
135
+
136
+ this._applyModeAndDefaults(mode, wasOff && turningOn).catch(err =>
140
137
  this.platform.log.error(`[${config.name}] setOperatingMode failed: ${err}`),
141
138
  );
142
139
  });
@@ -162,7 +159,7 @@ export class BedJetAccessory {
162
159
  const mode = this.config.defaultMode
163
160
  ? DEFAULT_MODE_MAP[this.config.defaultMode]
164
161
  : OperatingMode.HEAT;
165
- this._applyModeAndDefaults(mode, true, true).catch(err =>
162
+ this._applyModeAndDefaults(mode, true).catch(err =>
166
163
  this.platform.log.error(`[${config.name}] turn on failed: ${err}`),
167
164
  );
168
165
  }
@@ -211,7 +208,6 @@ export class BedJetAccessory {
211
208
  private async _applyModeAndDefaults(
212
209
  mode: OperatingMode,
213
210
  applyDefaults: boolean,
214
- applyMode: boolean,
215
211
  ): Promise<void> {
216
212
  const { config } = this;
217
213
 
package/src/platform.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { API, DynamicPlatformPlugin, Logging, PlatformAccessory, PlatformConfig } from 'homebridge';
2
2
  import { BedJetAccessory } from './accessory';
3
3
  import type { BedJetConfig } from './bedjet/types';
4
+ import { sanitizeName } from './utils';
4
5
 
5
6
  export const PLATFORM_NAME = 'BedJetPlatform';
6
7
  export const PLUGIN_NAME = 'homebridge-bedjet';
@@ -45,15 +46,18 @@ export class BedJetPlatform implements DynamicPlatformPlugin {
45
46
  this.discoveredUUIDs.push(uuid);
46
47
 
47
48
  const existing = this.accessories.get(uuid);
49
+ const safeName = sanitizeName(device.name);
48
50
 
49
51
  if (existing) {
50
52
  this.log.info('Restoring existing accessory from cache:', existing.displayName);
51
53
  existing.context.device = device;
54
+ // Update the display name in case the config name changed or was invalid
55
+ existing.displayName = safeName;
52
56
  this.api.updatePlatformAccessories([existing]);
53
57
  new BedJetAccessory(this, existing, device);
54
58
  } else {
55
- this.log.info('Adding new accessory:', device.name);
56
- const accessory = new this.api.platformAccessory(device.name, uuid);
59
+ this.log.info('Adding new accessory:', safeName);
60
+ const accessory = new this.api.platformAccessory(safeName, uuid);
57
61
  accessory.context.device = device;
58
62
  new BedJetAccessory(this, accessory, device);
59
63
  this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
package/src/utils.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * HomeKit only allows alphanumeric, space, and apostrophe characters in
3
+ * accessory/service names, starting and ending with an alphanumeric character.
4
+ * Underscores and other punctuation cause HAP warnings and may prevent the
5
+ * accessory from being added to the Home app.
6
+ */
7
+ export function sanitizeName(name: string): string {
8
+ return name
9
+ .replace(/_/g, ' ') // underscores → spaces
10
+ .replace(/[^a-zA-Z0-9 ']/g, ' ') // other invalid chars → space
11
+ .replace(/\s+/g, ' ') // collapse runs of spaces
12
+ .trim()
13
+ .replace(/^[^a-zA-Z0-9]+/, '') // must start with alphanumeric
14
+ .replace(/[^a-zA-Z0-9]+$/, '') // must end with alphanumeric
15
+ || 'BedJet';
16
+ }