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 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
+ }