homebridge-bedjet 0.3.3 → 0.3.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/config.schema.json +5 -5
- package/dist/accessory.js +12 -17
- package/dist/platform.js +6 -2
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +20 -0
- package/homebridge-ui/public/index.html +14 -6
- package/package.json +1 -1
- package/src/accessory.ts +11 -16
- package/src/bedjet/types.ts +1 -1
- package/src/platform.ts +6 -2
- package/src/utils.ts +16 -0
package/config.schema.json
CHANGED
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"description": "Mode to activate when the BedJet is turned on from HomeKit"
|
|
47
47
|
},
|
|
48
48
|
"defaultTemperature": {
|
|
49
|
-
"title": "Default Temperature °
|
|
49
|
+
"title": "Default Temperature °F (when turned on)",
|
|
50
50
|
"type": "number",
|
|
51
|
-
"minimum":
|
|
52
|
-
"maximum":
|
|
53
|
-
"multipleOf":
|
|
54
|
-
"description": "Target temperature to set when turned on. Range:
|
|
51
|
+
"minimum": 66,
|
|
52
|
+
"maximum": 109,
|
|
53
|
+
"multipleOf": 1,
|
|
54
|
+
"description": "Target temperature to set when turned on, in °F. Range: 66–109°F. Leave blank to keep the BedJet's last-used temperature."
|
|
55
55
|
},
|
|
56
56
|
"defaultFanSpeed": {
|
|
57
57
|
"title": "Default Fan Speed % (when turned on)",
|
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);
|
|
@@ -184,8 +171,16 @@ class BedJetAccessory {
|
|
|
184
171
|
await this.bedjet.setOperatingMode(mode);
|
|
185
172
|
if (applyDefaults) {
|
|
186
173
|
if (config.defaultTemperature !== undefined) {
|
|
187
|
-
|
|
188
|
-
|
|
174
|
+
// Config stores °F (values > 43 are unambiguously Fahrenheit).
|
|
175
|
+
// Old configs stored °C (≤ 43) — leave those as-is for backward compat.
|
|
176
|
+
let tempC = config.defaultTemperature;
|
|
177
|
+
if (tempC > 43) {
|
|
178
|
+
tempC = (tempC - 32) * 5 / 9;
|
|
179
|
+
}
|
|
180
|
+
// Clamp to BedJet V3 valid range 19–43 °C, rounded to nearest 0.5
|
|
181
|
+
tempC = Math.max(19, Math.min(43, Math.round(tempC * 2) / 2));
|
|
182
|
+
this.setPending(tempC, 'pendingTemp', 'pendingTempTimer', 5000);
|
|
183
|
+
await this.bedjet.setTemperature(tempC);
|
|
189
184
|
}
|
|
190
185
|
if (config.defaultFanSpeed !== undefined) {
|
|
191
186
|
this.setPending(config.defaultFanSpeed, 'pendingFanSpeed', 'pendingFanSpeedTimer', 5000);
|
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
|
|
@@ -362,19 +362,27 @@
|
|
|
362
362
|
modeField.appendChild(modeSelect);
|
|
363
363
|
row.appendChild(modeField);
|
|
364
364
|
|
|
365
|
-
// Temperature
|
|
365
|
+
// Temperature — stored and entered in °F.
|
|
366
|
+
// Old configs may have stored °C (≤ 43); convert those to °F for display.
|
|
367
|
+
var tempF = null;
|
|
368
|
+
if (currentTemp != null) {
|
|
369
|
+
tempF = currentTemp > 43
|
|
370
|
+
? Math.round(currentTemp) // already °F
|
|
371
|
+
: Math.round(currentTemp * 9 / 5 + 32); // was °C — convert for display
|
|
372
|
+
}
|
|
373
|
+
|
|
366
374
|
var tempField = document.createElement('div');
|
|
367
375
|
tempField.className = 'field';
|
|
368
376
|
var tempLabel = document.createElement('label');
|
|
369
|
-
tempLabel.textContent = 'Temp °
|
|
377
|
+
tempLabel.textContent = 'Temp °F';
|
|
370
378
|
var tempInput = document.createElement('input');
|
|
371
379
|
tempInput.type = 'number';
|
|
372
380
|
tempInput.className = 'field-temp';
|
|
373
|
-
tempInput.min = '
|
|
374
|
-
tempInput.max = '
|
|
375
|
-
tempInput.step = '
|
|
381
|
+
tempInput.min = '66';
|
|
382
|
+
tempInput.max = '109';
|
|
383
|
+
tempInput.step = '1';
|
|
376
384
|
tempInput.placeholder = 'Optional';
|
|
377
|
-
if (
|
|
385
|
+
if (tempF !== null) tempInput.value = tempF;
|
|
378
386
|
tempField.appendChild(tempLabel);
|
|
379
387
|
tempField.appendChild(tempInput);
|
|
380
388
|
row.appendChild(tempField);
|
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> = {
|
|
@@ -235,8 +222,16 @@ export class BedJetAccessory {
|
|
|
235
222
|
|
|
236
223
|
if (applyDefaults) {
|
|
237
224
|
if (config.defaultTemperature !== undefined) {
|
|
238
|
-
|
|
239
|
-
|
|
225
|
+
// Config stores °F (values > 43 are unambiguously Fahrenheit).
|
|
226
|
+
// Old configs stored °C (≤ 43) — leave those as-is for backward compat.
|
|
227
|
+
let tempC = config.defaultTemperature;
|
|
228
|
+
if (tempC > 43) {
|
|
229
|
+
tempC = (tempC - 32) * 5 / 9;
|
|
230
|
+
}
|
|
231
|
+
// Clamp to BedJet V3 valid range 19–43 °C, rounded to nearest 0.5
|
|
232
|
+
tempC = Math.max(19, Math.min(43, Math.round(tempC * 2) / 2));
|
|
233
|
+
this.setPending(tempC, 'pendingTemp', 'pendingTempTimer', 5000);
|
|
234
|
+
await this.bedjet.setTemperature(tempC);
|
|
240
235
|
}
|
|
241
236
|
if (config.defaultFanSpeed !== undefined) {
|
|
242
237
|
this.setPending(config.defaultFanSpeed, 'pendingFanSpeed', 'pendingFanSpeedTimer', 5000);
|
package/src/bedjet/types.ts
CHANGED
|
@@ -27,7 +27,7 @@ export interface BedJetConfig {
|
|
|
27
27
|
address: string; // BLE MAC e.g. "AA:BB:CC:DD:EE:FF"
|
|
28
28
|
scanTimeout?: number; // seconds (default 30)
|
|
29
29
|
defaultMode?: DefaultMode; // mode to activate when turned on from HomeKit
|
|
30
|
-
defaultTemperature?: number; // °C
|
|
30
|
+
defaultTemperature?: number; // °F (values >43 treated as °F; ≤43 treated as °C for backward compat)
|
|
31
31
|
defaultFanSpeed?: number; // percent 5–100, applied on turn-on
|
|
32
32
|
}
|
|
33
33
|
|
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
|
+
}
|