homebridge-bedjet 0.1.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/README.md +115 -0
- package/config.schema.json +39 -0
- package/dist/accessory.d.ts +15 -0
- package/dist/accessory.js +136 -0
- package/dist/accessory.js.map +1 -0
- package/dist/bedjet/BedJet.d.ts +42 -0
- package/dist/bedjet/BedJet.js +330 -0
- package/dist/bedjet/BedJet.js.map +1 -0
- package/dist/bedjet/constants.d.ts +63 -0
- package/dist/bedjet/constants.js +84 -0
- package/dist/bedjet/constants.js.map +1 -0
- package/dist/bedjet/types.d.ts +27 -0
- package/dist/bedjet/types.js +19 -0
- package/dist/bedjet/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +13 -0
- package/dist/platform.js +62 -0
- package/dist/platform.js.map +1 -0
- package/package.json +26 -0
- package/src/accessory.ts +195 -0
- package/src/bedjet/BedJet.ts +400 -0
- package/src/bedjet/constants.ts +83 -0
- package/src/bedjet/types.ts +44 -0
- package/src/index.ts +6 -0
- package/src/platform.ts +71 -0
- package/tsconfig.json +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# homebridge-bedjet
|
|
2
|
+
|
|
3
|
+
Homebridge plugin for the **BedJet V3** climate comfort system via Bluetooth LE.
|
|
4
|
+
|
|
5
|
+
Exposes a **Thermostat** and a **Fan** accessory in HomeKit so you can control temperature and fan speed from the Home app, Siri, or automations — without needing the BedJet cloud or the BedJet mobile app running.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Direct BLE connection from the Homebridge host (no cloud required)
|
|
10
|
+
- Thermostat service: current/target temperature, heating/cooling mode
|
|
11
|
+
- FanV2 service: on/off and rotation speed (5–100%)
|
|
12
|
+
- Automatic reconnection with exponential backoff (up to 5 attempts)
|
|
13
|
+
- Multi-device support (dual-zone BedJet setup)
|
|
14
|
+
- 60-second inactivity disconnect to share the BLE slot with the BedJet app
|
|
15
|
+
|
|
16
|
+
## Prerequisites
|
|
17
|
+
|
|
18
|
+
### Linux / Raspberry Pi
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# BlueZ and BLE dev headers
|
|
22
|
+
sudo apt-get install bluetooth bluez libbluetooth-dev libudev-dev
|
|
23
|
+
|
|
24
|
+
# Grant Node.js BLE access without root
|
|
25
|
+
sudo setcap cap_net_raw+eip $(eval readlink -f $(which node))
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### macOS
|
|
29
|
+
|
|
30
|
+
Works out of the box. A CoreBluetooth permission prompt will appear on first run. Grant it.
|
|
31
|
+
|
|
32
|
+
## Finding your BedJet MAC address
|
|
33
|
+
|
|
34
|
+
**Linux:**
|
|
35
|
+
```bash
|
|
36
|
+
sudo hcitool lescan
|
|
37
|
+
# Look for a line like: AA:BB:CC:DD:EE:FF BedJet
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**macOS / iOS / Android:** Use the [nRF Connect](https://www.nordicsemi.com/Products/Development-tools/nRF-Connect-for-mobile) app — it lists nearby BLE devices and their MAC addresses.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install -g homebridge-bedjet
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or install via the Homebridge UI — search for `homebridge-bedjet`.
|
|
49
|
+
|
|
50
|
+
## Configuration
|
|
51
|
+
|
|
52
|
+
Add to your `~/.homebridge/config.json`:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"platforms": [
|
|
57
|
+
{
|
|
58
|
+
"platform": "BedJetPlatform",
|
|
59
|
+
"devices": [
|
|
60
|
+
{
|
|
61
|
+
"name": "Bedroom BedJet",
|
|
62
|
+
"address": "AA:BB:CC:DD:EE:FF"
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
For a dual-zone setup, add both units:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"platforms": [
|
|
75
|
+
{
|
|
76
|
+
"platform": "BedJetPlatform",
|
|
77
|
+
"devices": [
|
|
78
|
+
{ "name": "Left Side BedJet", "address": "AA:BB:CC:DD:EE:FF" },
|
|
79
|
+
{ "name": "Right Side BedJet", "address": "11:22:33:44:55:66" }
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Config options
|
|
87
|
+
|
|
88
|
+
| Field | Required | Default | Description |
|
|
89
|
+
|-------|----------|---------|-------------|
|
|
90
|
+
| `name` | Yes | — | Display name in HomeKit |
|
|
91
|
+
| `address` | Yes | — | BLE MAC address of your BedJet V3 |
|
|
92
|
+
| `scanTimeout` | No | `30` | Seconds to scan before giving up on first connect |
|
|
93
|
+
|
|
94
|
+
## BedJet BLE limitation
|
|
95
|
+
|
|
96
|
+
The BedJet V3 only allows **one active BLE connection at a time**. The BedJet mobile app must be fully closed (not just backgrounded) before this plugin can connect.
|
|
97
|
+
|
|
98
|
+
This plugin automatically disconnects after **60 seconds of inactivity** to free the BLE slot for app use if needed. It will reconnect automatically the next time you interact with the accessory in HomeKit.
|
|
99
|
+
|
|
100
|
+
## HomeKit behaviour
|
|
101
|
+
|
|
102
|
+
| HomeKit control | BedJet action |
|
|
103
|
+
|---|---|
|
|
104
|
+
| Thermostat → Off | Standby (fan off) |
|
|
105
|
+
| Thermostat → Heat | Standard heat mode |
|
|
106
|
+
| Thermostat → Cool | Fan-only mode (BedJet has no compressor) |
|
|
107
|
+
| Thermostat → Auto | Heat mode |
|
|
108
|
+
| Temperature slider | SET_TEMPERATURE command |
|
|
109
|
+
| Fan → Off | Standby |
|
|
110
|
+
| Fan → On | Heat mode (if currently off) |
|
|
111
|
+
| Fan speed slider | SET_FAN command (5–100% in 5% steps) |
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pluginAlias": "BedJetPlatform",
|
|
3
|
+
"pluginType": "platform",
|
|
4
|
+
"singular": false,
|
|
5
|
+
"schema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"devices": {
|
|
9
|
+
"title": "BedJet Devices",
|
|
10
|
+
"type": "array",
|
|
11
|
+
"items": {
|
|
12
|
+
"title": "BedJet Device",
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"name": {
|
|
16
|
+
"title": "Display Name",
|
|
17
|
+
"type": "string",
|
|
18
|
+
"required": true,
|
|
19
|
+
"default": "BedJet"
|
|
20
|
+
},
|
|
21
|
+
"address": {
|
|
22
|
+
"title": "Bluetooth MAC Address",
|
|
23
|
+
"type": "string",
|
|
24
|
+
"required": true,
|
|
25
|
+
"placeholder": "AA:BB:CC:DD:EE:FF",
|
|
26
|
+
"description": "BLE MAC address of your BedJet V3. On Linux, find it with: sudo hcitool lescan"
|
|
27
|
+
},
|
|
28
|
+
"scanTimeout": {
|
|
29
|
+
"title": "Scan Timeout (seconds)",
|
|
30
|
+
"type": "integer",
|
|
31
|
+
"default": 30,
|
|
32
|
+
"description": "How long to scan for the device before giving up (default: 30)"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PlatformAccessory } from 'homebridge';
|
|
2
|
+
import type { BedJetConfig } from './bedjet/types';
|
|
3
|
+
import type { BedJetPlatform } from './platform';
|
|
4
|
+
export declare class BedJetAccessory {
|
|
5
|
+
private readonly platform;
|
|
6
|
+
private readonly accessory;
|
|
7
|
+
private readonly config;
|
|
8
|
+
private readonly thermostatService;
|
|
9
|
+
private readonly fanService;
|
|
10
|
+
private readonly bedjet;
|
|
11
|
+
private tempDebounce;
|
|
12
|
+
private fanDebounce;
|
|
13
|
+
constructor(platform: BedJetPlatform, accessory: PlatformAccessory, config: BedJetConfig);
|
|
14
|
+
private _syncHomeKit;
|
|
15
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BedJetAccessory = void 0;
|
|
4
|
+
const BedJet_1 = require("./bedjet/BedJet");
|
|
5
|
+
const constants_1 = require("./bedjet/constants");
|
|
6
|
+
// OperatingMode → CurrentHeatingCoolingState value
|
|
7
|
+
const CURRENT_STATE_MAP = {
|
|
8
|
+
[constants_1.OperatingMode.STANDBY]: 0, // OFF
|
|
9
|
+
[constants_1.OperatingMode.HEAT]: 1, // HEAT
|
|
10
|
+
[constants_1.OperatingMode.TURBO]: 1, // HEAT
|
|
11
|
+
[constants_1.OperatingMode.EXTENDED_HEAT]: 1, // HEAT
|
|
12
|
+
[constants_1.OperatingMode.COOL]: 2, // COOL
|
|
13
|
+
[constants_1.OperatingMode.DRY]: 2, // COOL
|
|
14
|
+
[constants_1.OperatingMode.WAIT]: 0, // OFF
|
|
15
|
+
};
|
|
16
|
+
// TargetHeatingCoolingState value → OperatingMode
|
|
17
|
+
const TARGET_TO_MODE = {
|
|
18
|
+
0: constants_1.OperatingMode.STANDBY,
|
|
19
|
+
1: constants_1.OperatingMode.HEAT,
|
|
20
|
+
2: constants_1.OperatingMode.COOL,
|
|
21
|
+
3: constants_1.OperatingMode.HEAT, // AUTO — fall back to heat
|
|
22
|
+
};
|
|
23
|
+
class BedJetAccessory {
|
|
24
|
+
constructor(platform, accessory, config) {
|
|
25
|
+
this.platform = platform;
|
|
26
|
+
this.accessory = accessory;
|
|
27
|
+
this.config = config;
|
|
28
|
+
// Debounce handles for setter commands
|
|
29
|
+
this.tempDebounce = null;
|
|
30
|
+
this.fanDebounce = null;
|
|
31
|
+
const { Service, Characteristic } = platform.api.hap;
|
|
32
|
+
// AccessoryInformation
|
|
33
|
+
const infoService = this.accessory.getService(Service.AccessoryInformation)
|
|
34
|
+
?? this.accessory.addService(Service.AccessoryInformation);
|
|
35
|
+
infoService
|
|
36
|
+
.setCharacteristic(Characteristic.Manufacturer, 'BedJet')
|
|
37
|
+
.setCharacteristic(Characteristic.Model, 'BedJet 3')
|
|
38
|
+
.setCharacteristic(Characteristic.SerialNumber, config.address);
|
|
39
|
+
// Thermostat service
|
|
40
|
+
this.thermostatService = this.accessory.getService(Service.Thermostat)
|
|
41
|
+
?? this.accessory.addService(Service.Thermostat, config.name, 'thermostat');
|
|
42
|
+
this.thermostatService.getCharacteristic(Characteristic.TemperatureDisplayUnits)
|
|
43
|
+
.onGet(() => Characteristic.TemperatureDisplayUnits.CELSIUS);
|
|
44
|
+
this.thermostatService.getCharacteristic(Characteristic.CurrentTemperature)
|
|
45
|
+
.onGet(() => this.bedjet.state.currentTemperature);
|
|
46
|
+
this.thermostatService.getCharacteristic(Characteristic.TargetTemperature)
|
|
47
|
+
.setProps({ minValue: 19, maxValue: 43, minStep: 0.5 })
|
|
48
|
+
.onGet(() => this.bedjet.state.targetTemperature)
|
|
49
|
+
.onSet((value) => {
|
|
50
|
+
if (this.tempDebounce) {
|
|
51
|
+
clearTimeout(this.tempDebounce);
|
|
52
|
+
}
|
|
53
|
+
this.tempDebounce = setTimeout(() => {
|
|
54
|
+
this.bedjet.setTemperature(value).catch(err => this.platform.log.error(`[${config.name}] setTemperature failed: ${err}`));
|
|
55
|
+
}, 100);
|
|
56
|
+
});
|
|
57
|
+
this.thermostatService.getCharacteristic(Characteristic.CurrentHeatingCoolingState)
|
|
58
|
+
.onGet(() => CURRENT_STATE_MAP[this.bedjet.state.operatingMode] ?? 0);
|
|
59
|
+
this.thermostatService.getCharacteristic(Characteristic.TargetHeatingCoolingState)
|
|
60
|
+
.onGet(() => {
|
|
61
|
+
const mode = this.bedjet.state.operatingMode;
|
|
62
|
+
if (mode === constants_1.OperatingMode.STANDBY || mode === constants_1.OperatingMode.WAIT)
|
|
63
|
+
return 0;
|
|
64
|
+
if (mode === constants_1.OperatingMode.COOL || mode === constants_1.OperatingMode.DRY)
|
|
65
|
+
return 2;
|
|
66
|
+
return 1; // HEAT / TURBO / EXTENDED_HEAT
|
|
67
|
+
})
|
|
68
|
+
.onSet((value) => {
|
|
69
|
+
const mode = TARGET_TO_MODE[value] ?? constants_1.OperatingMode.STANDBY;
|
|
70
|
+
this.bedjet.setOperatingMode(mode).catch(err => this.platform.log.error(`[${config.name}] setOperatingMode failed: ${err}`));
|
|
71
|
+
});
|
|
72
|
+
// FanV2 service
|
|
73
|
+
this.fanService = this.accessory.getService(Service.Fanv2)
|
|
74
|
+
?? this.accessory.addService(Service.Fanv2, `${config.name} Fan`, 'fan');
|
|
75
|
+
this.fanService.getCharacteristic(Characteristic.Active)
|
|
76
|
+
.onGet(() => this.bedjet.state.operatingMode !== constants_1.OperatingMode.STANDBY
|
|
77
|
+
? Characteristic.Active.ACTIVE
|
|
78
|
+
: Characteristic.Active.INACTIVE)
|
|
79
|
+
.onSet((value) => {
|
|
80
|
+
if (value === Characteristic.Active.INACTIVE) {
|
|
81
|
+
this.bedjet.setOperatingMode(constants_1.OperatingMode.STANDBY).catch(err => this.platform.log.error(`[${config.name}] setOperatingMode(STANDBY) failed: ${err}`));
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// Only turn on if currently off
|
|
85
|
+
if (this.bedjet.state.operatingMode === constants_1.OperatingMode.STANDBY) {
|
|
86
|
+
this.bedjet.setOperatingMode(constants_1.OperatingMode.HEAT).catch(err => this.platform.log.error(`[${config.name}] setOperatingMode(HEAT) failed: ${err}`));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
this.fanService.getCharacteristic(Characteristic.RotationSpeed)
|
|
91
|
+
.setProps({ minValue: 5, maxValue: 100, minStep: 5 })
|
|
92
|
+
.onGet(() => this.bedjet.state.fanSpeed)
|
|
93
|
+
.onSet((value) => {
|
|
94
|
+
if (this.fanDebounce) {
|
|
95
|
+
clearTimeout(this.fanDebounce);
|
|
96
|
+
}
|
|
97
|
+
this.fanDebounce = setTimeout(() => {
|
|
98
|
+
this.bedjet.setFanSpeed(value).catch(err => this.platform.log.error(`[${config.name}] setFanSpeed failed: ${err}`));
|
|
99
|
+
}, 100);
|
|
100
|
+
});
|
|
101
|
+
// Create BLE client and wire up state change events
|
|
102
|
+
this.bedjet = new BedJet_1.BedJet(config, platform.log);
|
|
103
|
+
this.bedjet.on('stateChange', (state) => this._syncHomeKit(state));
|
|
104
|
+
this.bedjet.on('connected', () => {
|
|
105
|
+
// Update FirmwareRevision once we have it
|
|
106
|
+
const fw = this.bedjet.firmware;
|
|
107
|
+
if (fw) {
|
|
108
|
+
infoService.setCharacteristic(Characteristic.FirmwareRevision, fw);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
// Start connecting — errors are logged but don't crash Homebridge
|
|
112
|
+
this.bedjet.connect().catch(err => this.platform.log.error(`[${config.name}] Initial connect failed: ${err}`));
|
|
113
|
+
}
|
|
114
|
+
_syncHomeKit(state) {
|
|
115
|
+
const { Characteristic } = this.platform.api.hap;
|
|
116
|
+
// Update TargetTemperature bounds from live packet values
|
|
117
|
+
this.thermostatService
|
|
118
|
+
.getCharacteristic(Characteristic.TargetTemperature)
|
|
119
|
+
.setProps({ minValue: state.minimumTemperature, maxValue: state.maximumTemperature });
|
|
120
|
+
this.thermostatService.updateCharacteristic(Characteristic.CurrentTemperature, state.currentTemperature);
|
|
121
|
+
this.thermostatService.updateCharacteristic(Characteristic.TargetTemperature, state.targetTemperature);
|
|
122
|
+
this.thermostatService.updateCharacteristic(Characteristic.CurrentHeatingCoolingState, CURRENT_STATE_MAP[state.operatingMode] ?? 0);
|
|
123
|
+
const targetState = state.operatingMode === constants_1.OperatingMode.STANDBY || state.operatingMode === constants_1.OperatingMode.WAIT
|
|
124
|
+
? 0
|
|
125
|
+
: state.operatingMode === constants_1.OperatingMode.COOL || state.operatingMode === constants_1.OperatingMode.DRY
|
|
126
|
+
? 2
|
|
127
|
+
: 1;
|
|
128
|
+
this.thermostatService.updateCharacteristic(Characteristic.TargetHeatingCoolingState, targetState);
|
|
129
|
+
this.fanService.updateCharacteristic(Characteristic.Active, state.operatingMode !== constants_1.OperatingMode.STANDBY
|
|
130
|
+
? Characteristic.Active.ACTIVE
|
|
131
|
+
: Characteristic.Active.INACTIVE);
|
|
132
|
+
this.fanService.updateCharacteristic(Characteristic.RotationSpeed, state.fanSpeed);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
exports.BedJetAccessory = BedJetAccessory;
|
|
136
|
+
//# sourceMappingURL=accessory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessory.js","sourceRoot":"","sources":["../src/accessory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import type { Logger } from 'homebridge';
|
|
3
|
+
import { OperatingMode, BedJetButton } from './constants';
|
|
4
|
+
import type { BedJetConfig, BedJetState } from './types';
|
|
5
|
+
export declare class BedJet extends EventEmitter {
|
|
6
|
+
private readonly config;
|
|
7
|
+
private readonly log;
|
|
8
|
+
private peripheral;
|
|
9
|
+
private commandChar;
|
|
10
|
+
private statusChar;
|
|
11
|
+
private disconnectTimer;
|
|
12
|
+
private staleTimer;
|
|
13
|
+
private reconnectAttempts;
|
|
14
|
+
private connecting;
|
|
15
|
+
private _state;
|
|
16
|
+
private deviceName;
|
|
17
|
+
private firmwareVersion;
|
|
18
|
+
constructor(config: BedJetConfig, log: Logger);
|
|
19
|
+
get state(): BedJetState;
|
|
20
|
+
get name(): string;
|
|
21
|
+
get firmware(): string | null;
|
|
22
|
+
connect(): Promise<void>;
|
|
23
|
+
private _scan;
|
|
24
|
+
private _connectPeripheral;
|
|
25
|
+
private _handleNotification;
|
|
26
|
+
private _handleStatusRead;
|
|
27
|
+
private _readDeviceName;
|
|
28
|
+
private _readDeviceStatus;
|
|
29
|
+
private _sendCommand;
|
|
30
|
+
setTemperature(celsius: number): Promise<void>;
|
|
31
|
+
setFanSpeed(percent: number): Promise<void>;
|
|
32
|
+
setOperatingMode(mode: OperatingMode): Promise<void>;
|
|
33
|
+
pressButton(button: BedJetButton): Promise<void>;
|
|
34
|
+
setClock(hour: number, minute: number): Promise<void>;
|
|
35
|
+
setRuntimeRemaining(hours: number, minutes: number): Promise<void>;
|
|
36
|
+
setLed(on: boolean): Promise<void>;
|
|
37
|
+
setMuted(muted: boolean): Promise<void>;
|
|
38
|
+
private _resetDisconnectTimer;
|
|
39
|
+
private _resetStaleTimer;
|
|
40
|
+
private _onDisconnected;
|
|
41
|
+
disconnect(): Promise<void>;
|
|
42
|
+
}
|