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 +18 -22
- package/dist/platform.js +6 -2
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +20 -0
- package/package.json +1 -1
- package/src/accessory.ts +17 -21
- package/src/platform.ts +6 -2
- package/src/utils.ts +16 -0
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
|
-
|
|
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 =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
|
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
|
|
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:',
|
|
46
|
-
const accessory = new this.api.platformAccessory(
|
|
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]);
|
package/dist/utils.d.ts
ADDED
|
@@ -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
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
|
-
|
|
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 =
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
|
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:',
|
|
56
|
-
const accessory = new this.api.platformAccessory(
|
|
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
|
+
}
|