homebridge-broadlink-rm-blaster 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luud Jacobs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # homebridge-broadlink-rm-blaster
2
+
3
+ Blast RF and IR signals from Broadlink RM devices using Homebridge. Inspired by
4
+ [homebridge-broadlink-rm](https://github.com/kiwi-cam/homebridge-broadlink-rm#readme),
5
+ built on [kiwicam-broadlinkjs-rm](https://www.npmjs.com/package/kiwicam-broadlinkjs-rm)
6
+ for the underlying device communication.
7
+
8
+ This plugin sends pre-recorded hex signals to a known device IP. **It does not learn
9
+ signals or autodiscover the Broadlink devices.** To capture hex codes from your own
10
+ remotes, see [learn-broadlink-rm4-codes](https://github.com/LuudJacobs/learn-broadlink-rm4-codes).
11
+
12
+ > This project was vibe coded using Claude
13
+
14
+ ## Features
15
+
16
+ - **Multiple RM devices** configure several Broadlink RMs and assign each
17
+ accessory to whichever one it's actually near.
18
+ - **Basic accessories** power on/off via a hex signal.
19
+ - **Dimmer lights** one hex signal per discrete brightness level
20
+ - **TVs** power on/off plus a usable remote (arrows, select, back, exit, info,
21
+ volume, mute) in the iOS Remote app
22
+ - **Temperature/humidity sensor** polls the RM every 60 seconds, on by default.
23
+ - Fully configurable via the Homebridge Config UI X plugin settings form.
24
+
25
+ ## Setup and Usage
26
+
27
+ ```bash
28
+ npm install -g homebridge-broadlink-rm-blaster
29
+ ```
30
+
31
+ ### Unlock device
32
+
33
+ Your Broadlink RM must be unlocked using the official Broadlink app before this
34
+ plugin (or any third-party integration) can control it: new devices ship locked,
35
+ which blocks local API access.
36
+
37
+ ### TVs
38
+
39
+ **TVs don't appear automatically alongside your other accessories.** HomeKit
40
+ only shows a proper TV tile/remote when it's added as its own accessory, so
41
+ each one needs to be paired separately: after restarting Homebridge, check
42
+ its log for a line like `Please add [name] manually in Home app. Setup
43
+ Code: ...` for each configured TV, then add it in the Home app using that
44
+ code, the same way you'd add any other HomeKit accessory. If you remove a
45
+ TV from your config later, it has to be removed from the Home app manually
46
+ too since Homebridge can't unpair it for you.
47
+
48
+ ## Configuration
49
+
50
+ This plugin can be fully configured from the Homebridge Config UI X plugin
51
+ settings form.
52
+
53
+ ### config.json
54
+
55
+ If you'd rather edit the config file directly, here's an example
56
+ `config.json` platform block:
57
+
58
+ ```json
59
+ {
60
+ "platform": "BroadlinkRMBlaster",
61
+ "rmDevices": [
62
+ {
63
+ "name": "Default RM",
64
+ "ip": "192.168.1.50",
65
+ "enableTemperatureHumidity": true
66
+ },
67
+ {
68
+ "name": "Bedroom RM",
69
+ "ip": "192.168.1.60"
70
+ }
71
+ ],
72
+ "accessories": [
73
+ {
74
+ "name": "Living Room Lamp",
75
+ "rmDevice": "Default RM",
76
+ "accessoryType": "light",
77
+ "powerOnCode": "2600...",
78
+ "powerOffCode": "2600..."
79
+ },
80
+ {
81
+ "name": "Fan",
82
+ "rmDevice": "Bedroom RM",
83
+ "accessoryType": "fan",
84
+ "powerOnCode": "2600..."
85
+ }
86
+ ],
87
+ "dimmers": [
88
+ {
89
+ "name": "Bedroom Dimmer",
90
+ "rmDevice": "Bedroom RM",
91
+ "powerOnCode": "2600...",
92
+ "powerOffCode": "2600...",
93
+ "zeroPercentCode": "2600...",
94
+ "hundredPercentCode": "2600...",
95
+ "debounceSeconds": 0.5,
96
+ "useLastKnownBrightness": true,
97
+ "useDefaultBrightnessLevel": true,
98
+ "defaultBrightnessLevel": 75,
99
+ "useMaxBrightnessLevel": true,
100
+ "maxBrightnessLevel": 50,
101
+ "levels": [
102
+ { "level": 25, "code": "2600..." },
103
+ { "level": 50, "code": "2600..." },
104
+ { "level": 75, "code": "2600..." }
105
+ ]
106
+ }
107
+ ],
108
+ "tvs": [
109
+ {
110
+ "name": "Living Room TV",
111
+ "rmDevice": "Default RM",
112
+ "powerOnCode": "2600...",
113
+ "volumeUpCode": "2600...",
114
+ "volumeDownCode": "2600...",
115
+ "muteCode": "2600...",
116
+ "arrowUpCode": "2600...",
117
+ "selectCode": "2600..."
118
+ }
119
+ ]
120
+ }
121
+ ```
122
+
123
+ - `rmDevices`: at least one required. Each needs a unique `name` and `ip`;
124
+ `enableTemperatureHumidity` (defaults to `true`) adds a temperature/humidity
125
+ sensor accessory for that specific device.
126
+ - `rmDevice` on every accessory/dimmer/TV below is a plain text field that
127
+ must exactly match the `name` of one of the devices above. There's no
128
+ live dropdown, since Homebridge's config UI can't populate one from
129
+ sibling array data. Save your RM devices first, then reference them by
130
+ name; a typo just makes that accessory get skipped with a warning in the
131
+ log rather than silently misbehaving.
132
+ - `accessories[].powerOffCode`: optional; if omitted, the power-on signal is
133
+ reused for both on and off (useful for toggle-only remotes).
134
+ - `dimmers[].powerOnCode` / `powerOffCode`: required fields, but currently
135
+ unused by the plugin - power on/off is done with the resolved brightness
136
+ level and `zeroPercentCode` instead, as an ongoing experiment to reduce RF
137
+ traffic. Still required so this can be reverted without a config change.
138
+ - `dimmers[].defaultBrightnessLevel` / `maxBrightnessLevel`: independent target
139
+ percentages, not tied to a specific configured level. The nearest configured
140
+ signal is sent, but the percentage shown in Home stays the configured target.
141
+ - `dimmers[].hundredPercentCode`: required, like `zeroPercentCode`: the true,
142
+ uncapped 100% signal, always reachable regardless of any max brightness cap.
143
+ - `dimmers[].debounceSeconds`: defaults to `0.5`. A slider drag fires many
144
+ rapid updates; the actual signal only sends after this long of no movement.
145
+ - `tvs[].powerOnCode` is the only required TV field. Everything else
146
+ (`powerOffCode`, `volumeUpCode`/`volumeDownCode`, `muteCode`,
147
+ `arrowUpCode`/`arrowDownCode`/`arrowLeftCode`/`arrowRightCode`,
148
+ `selectCode`, `infoCode`, `backCode`, `exitCode`) is optional; pressing a
149
+ remote button with no signal configured for it just does nothing.
150
+ `muteCode` is sent as-is for both muting and unmuting, since most remotes
151
+ use a single toggle button rather than distinct on/off signals.
152
+
153
+ ## Debugging
154
+
155
+ To send a single hex code straight to your RM, bypassing Homebridge/HomeKit
156
+ entirely (useful for isolating whether a signal behaves oddly on the device
157
+ itself vs. through the plugin), run this in the Homebridge Config UI X
158
+ terminal:
159
+
160
+ ```bash
161
+ broadlink-rm-blaster <ip> <hexCode>
162
+ ```
163
+
164
+ Run `broadlink-rm-blaster --help` for usage details.
@@ -0,0 +1,365 @@
1
+ {
2
+ "pluginAlias": "BroadlinkRMBlaster",
3
+ "pluginType": "platform",
4
+ "singular": true,
5
+ "headerDisplay": "Blasts pre-recorded IR/RF hex signals via a Broadlink RM. Signals must be captured elsewhere (this plugin does not learn or discover devices).",
6
+ "schema": {
7
+ "type": "object",
8
+ "properties": {
9
+ "rmDevices": {
10
+ "title": "Broadlink RM Devices",
11
+ "type": "array",
12
+ "minItems": 1,
13
+ "required": true,
14
+ "items": {
15
+ "type": "object",
16
+ "properties": {
17
+ "name": {
18
+ "title": "Name",
19
+ "type": "string",
20
+ "required": true,
21
+ "default": "Default RM",
22
+ "description": "Referenced by name from each accessory below - must be unique."
23
+ },
24
+ "ip": {
25
+ "title": "IP Address",
26
+ "type": "string",
27
+ "format": "ipv4",
28
+ "required": true
29
+ },
30
+ "enableTemperatureHumidity": {
31
+ "title": "Show temperature and humidity if available",
32
+ "type": "boolean",
33
+ "default": true,
34
+ "required": false,
35
+ "description": "Not all RM units report real sensor data. If yours doesn't, this sensor will just show \"No Response\" in Home."
36
+ }
37
+ }
38
+ }
39
+ },
40
+ "accessories": {
41
+ "title": "Accessories",
42
+ "type": "array",
43
+ "items": {
44
+ "type": "object",
45
+ "properties": {
46
+ "name": {
47
+ "title": "Name",
48
+ "type": "string",
49
+ "required": true
50
+ },
51
+ "rmDevice": {
52
+ "title": "RM Device",
53
+ "type": "string",
54
+ "required": true,
55
+ "default": "Default RM",
56
+ "description": "Must match the Name of one of the RM devices configured above."
57
+ },
58
+ "accessoryType": {
59
+ "title": "Accessory Type",
60
+ "type": "string",
61
+ "required": true,
62
+ "default": "light",
63
+ "oneOf": [
64
+ { "title": "Light", "enum": ["light"] },
65
+ { "title": "Switch", "enum": ["switch"] },
66
+ { "title": "Outlet", "enum": ["outlet"] },
67
+ { "title": "Fan", "enum": ["fan"] }
68
+ ]
69
+ },
70
+ "powerOnCode": {
71
+ "title": "Power On Signal",
72
+ "type": "string",
73
+ "required": true,
74
+ "description": "Hex code sent to turn the accessory on."
75
+ },
76
+ "powerOffCode": {
77
+ "title": "Power Off Signal",
78
+ "type": "string",
79
+ "required": false,
80
+ "description": "Hex code sent to turn the accessory off. Leave empty to reuse the Power On signal (useful for toggle-only remotes)."
81
+ }
82
+ }
83
+ }
84
+ },
85
+ "dimmers": {
86
+ "title": "Dimmer Lights",
87
+ "type": "array",
88
+ "items": {
89
+ "type": "object",
90
+ "properties": {
91
+ "name": {
92
+ "title": "Name",
93
+ "type": "string",
94
+ "required": true
95
+ },
96
+ "rmDevice": {
97
+ "title": "RM Device",
98
+ "type": "string",
99
+ "required": true,
100
+ "default": "Default RM",
101
+ "description": "Must match the Name of one of the RM devices configured above."
102
+ },
103
+ "powerOnCode": {
104
+ "title": "Power On Signal",
105
+ "type": "string",
106
+ "required": true,
107
+ "description": "Hex code sent to turn the light on. Always used for powering on, regardless of the resolved brightness level."
108
+ },
109
+ "powerOffCode": {
110
+ "title": "Power Off Signal",
111
+ "type": "string",
112
+ "required": true,
113
+ "description": "Hex code sent to turn the light off. Always used, instead of the Brightness 0% signal."
114
+ },
115
+ "useLastKnownBrightness": {
116
+ "title": "Use Last Known Brightness",
117
+ "type": "boolean",
118
+ "required": false,
119
+ "description": "When turning on, restore the last brightness this light was set to instead of a default/max/highest level."
120
+ },
121
+ "useDefaultBrightnessLevel": {
122
+ "title": "Set Default Brightness Level",
123
+ "type": "boolean",
124
+ "required": false,
125
+ "description": "Used when turning on if last-known brightness doesn't apply."
126
+ },
127
+ "defaultBrightnessLevel": {
128
+ "title": "Default Brightness Level (%)",
129
+ "type": "integer",
130
+ "minimum": 0,
131
+ "maximum": 100,
132
+ "default": 50,
133
+ "required": false,
134
+ "condition": {
135
+ "functionBody": "return model.dimmers && model.dimmers[arrayIndices] && model.dimmers[arrayIndices].useDefaultBrightnessLevel === true;"
136
+ }
137
+ },
138
+ "useMaxBrightnessLevel": {
139
+ "title": "Set Max Brightness Level",
140
+ "type": "boolean",
141
+ "required": false,
142
+ "description": "Caps and remaps the 0-100% slider onto this percentage."
143
+ },
144
+ "maxBrightnessLevel": {
145
+ "title": "Max Brightness Level (%)",
146
+ "type": "integer",
147
+ "minimum": 0,
148
+ "maximum": 100,
149
+ "default": 100,
150
+ "required": false,
151
+ "condition": {
152
+ "functionBody": "return model.dimmers && model.dimmers[arrayIndices] && model.dimmers[arrayIndices].useMaxBrightnessLevel === true;"
153
+ }
154
+ },
155
+ "zeroPercentCode": {
156
+ "title": "Brightness 0% Signal",
157
+ "type": "string",
158
+ "required": true,
159
+ "description": "Hex code for the lowest (0%) brightness level."
160
+ },
161
+ "hundredPercentCode": {
162
+ "title": "Brightness 100% Signal",
163
+ "type": "string",
164
+ "required": true,
165
+ "description": "Hex code for true 100% brightness. Always the actual full-brightness signal, regardless of any max brightness cap set above."
166
+ },
167
+ "debounceSeconds": {
168
+ "title": "Debounce (seconds)",
169
+ "type": "number",
170
+ "minimum": 0,
171
+ "default": 0.5,
172
+ "required": false,
173
+ "description": "Wait this long after the slider stops moving before sending a signal, so dragging doesn't blast every intermediate position."
174
+ },
175
+ "levels": {
176
+ "title": "Brightness Levels",
177
+ "type": "array",
178
+ "minItems": 1,
179
+ "items": {
180
+ "type": "object",
181
+ "properties": {
182
+ "level": {
183
+ "title": "Brightness Level (%)",
184
+ "type": "integer",
185
+ "minimum": 1,
186
+ "maximum": 100,
187
+ "required": true
188
+ },
189
+ "code": {
190
+ "title": "Signal",
191
+ "type": "string",
192
+ "required": true
193
+ }
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+ },
200
+ "tvs": {
201
+ "title": "TVs",
202
+ "type": "array",
203
+ "items": {
204
+ "type": "object",
205
+ "properties": {
206
+ "name": {
207
+ "title": "Name",
208
+ "type": "string",
209
+ "required": true
210
+ },
211
+ "rmDevice": {
212
+ "title": "RM Device",
213
+ "type": "string",
214
+ "required": true,
215
+ "default": "Default RM",
216
+ "description": "Must match the Name of one of the RM devices configured above."
217
+ },
218
+ "powerOnCode": {
219
+ "title": "Power On Signal",
220
+ "type": "string",
221
+ "required": true,
222
+ "description": "Hex code sent to turn the TV on."
223
+ },
224
+ "powerOffCode": {
225
+ "title": "Power Off Signal",
226
+ "type": "string",
227
+ "required": false,
228
+ "description": "Hex code sent to turn the TV off. Leave empty to reuse the Power On signal (useful for toggle-only remotes)."
229
+ },
230
+ "volumeUpCode": {
231
+ "title": "Volume Up Signal",
232
+ "type": "string",
233
+ "required": false
234
+ },
235
+ "volumeDownCode": {
236
+ "title": "Volume Down Signal",
237
+ "type": "string",
238
+ "required": false
239
+ },
240
+ "muteCode": {
241
+ "title": "Mute Signal",
242
+ "type": "string",
243
+ "required": false,
244
+ "description": "Most remotes use a single toggle button for mute - the same signal is sent whether muting or unmuting."
245
+ },
246
+ "arrowUpCode": {
247
+ "title": "Arrow Up Signal",
248
+ "type": "string",
249
+ "required": false
250
+ },
251
+ "arrowDownCode": {
252
+ "title": "Arrow Down Signal",
253
+ "type": "string",
254
+ "required": false
255
+ },
256
+ "arrowLeftCode": {
257
+ "title": "Arrow Left Signal",
258
+ "type": "string",
259
+ "required": false
260
+ },
261
+ "arrowRightCode": {
262
+ "title": "Arrow Right Signal",
263
+ "type": "string",
264
+ "required": false
265
+ },
266
+ "selectCode": {
267
+ "title": "Select Signal",
268
+ "type": "string",
269
+ "required": false
270
+ },
271
+ "infoCode": {
272
+ "title": "Info Signal",
273
+ "type": "string",
274
+ "required": false
275
+ },
276
+ "backCode": {
277
+ "title": "Back Signal",
278
+ "type": "string",
279
+ "required": false
280
+ },
281
+ "exitCode": {
282
+ "title": "Exit Signal",
283
+ "type": "string",
284
+ "required": false
285
+ }
286
+ }
287
+ }
288
+ }
289
+ }
290
+ },
291
+ "layout": [
292
+ {
293
+ "type": "array",
294
+ "key": "rmDevices",
295
+ "title": "Broadlink RM Devices",
296
+ "items": [
297
+ "rmDevices[].name",
298
+ "rmDevices[].ip",
299
+ "rmDevices[].enableTemperatureHumidity"
300
+ ]
301
+ },
302
+ {
303
+ "type": "array",
304
+ "key": "accessories",
305
+ "title": "Accessories",
306
+ "items": [
307
+ "accessories[].name",
308
+ "accessories[].rmDevice",
309
+ "accessories[].accessoryType",
310
+ "accessories[].powerOnCode",
311
+ "accessories[].powerOffCode"
312
+ ]
313
+ },
314
+ {
315
+ "type": "array",
316
+ "key": "dimmers",
317
+ "title": "Dimmer Lights",
318
+ "items": [
319
+ "dimmers[].name",
320
+ "dimmers[].rmDevice",
321
+ "dimmers[].powerOnCode",
322
+ "dimmers[].powerOffCode",
323
+ "dimmers[].useLastKnownBrightness",
324
+ "dimmers[].useDefaultBrightnessLevel",
325
+ "dimmers[].defaultBrightnessLevel",
326
+ "dimmers[].useMaxBrightnessLevel",
327
+ "dimmers[].maxBrightnessLevel",
328
+ "dimmers[].zeroPercentCode",
329
+ "dimmers[].hundredPercentCode",
330
+ "dimmers[].debounceSeconds",
331
+ {
332
+ "type": "array",
333
+ "key": "dimmers[].levels",
334
+ "title": "Brightness Levels",
335
+ "items": [
336
+ "dimmers[].levels[].level",
337
+ "dimmers[].levels[].code"
338
+ ]
339
+ }
340
+ ]
341
+ },
342
+ {
343
+ "type": "array",
344
+ "key": "tvs",
345
+ "title": "TVs",
346
+ "items": [
347
+ "tvs[].name",
348
+ "tvs[].rmDevice",
349
+ "tvs[].powerOnCode",
350
+ "tvs[].powerOffCode",
351
+ "tvs[].volumeUpCode",
352
+ "tvs[].volumeDownCode",
353
+ "tvs[].muteCode",
354
+ "tvs[].arrowUpCode",
355
+ "tvs[].arrowDownCode",
356
+ "tvs[].arrowLeftCode",
357
+ "tvs[].arrowRightCode",
358
+ "tvs[].selectCode",
359
+ "tvs[].infoCode",
360
+ "tvs[].backCode",
361
+ "tvs[].exitCode"
362
+ ]
363
+ }
364
+ ]
365
+ }
@@ -0,0 +1,14 @@
1
+ import type { PlatformAccessory } from 'homebridge';
2
+ import type { BroadlinkRMBlasterPlatform } from '../platform';
3
+ import type { BasicAccessoryConfig } from '../configTypes';
4
+ export declare function selectPowerCode(config: Pick<BasicAccessoryConfig, 'powerOnCode' | 'powerOffCode'>, on: boolean): string;
5
+ export declare class BasicAccessory {
6
+ private readonly platform;
7
+ private readonly accessory;
8
+ private readonly config;
9
+ private readonly ip;
10
+ constructor(platform: BroadlinkRMBlasterPlatform, accessory: PlatformAccessory, config: BasicAccessoryConfig, ip: string);
11
+ private getOrCreateService;
12
+ private getOn;
13
+ private setOn;
14
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BasicAccessory = void 0;
4
+ exports.selectPowerCode = selectPowerCode;
5
+ function selectPowerCode(config, on) {
6
+ return on ? config.powerOnCode : (config.powerOffCode ?? config.powerOnCode);
7
+ }
8
+ class BasicAccessory {
9
+ platform;
10
+ accessory;
11
+ config;
12
+ ip;
13
+ constructor(platform, accessory, config, ip) {
14
+ this.platform = platform;
15
+ this.accessory = accessory;
16
+ this.config = config;
17
+ this.ip = ip;
18
+ const service = this.getOrCreateService();
19
+ service.setCharacteristic(this.platform.Characteristic.Name, this.config.name);
20
+ if (this.config.accessoryType === 'outlet') {
21
+ service.setCharacteristic(this.platform.Characteristic.OutletInUse, true);
22
+ }
23
+ service.getCharacteristic(this.platform.Characteristic.On)
24
+ .onGet(() => this.getOn())
25
+ .onSet((value) => this.setOn(value));
26
+ }
27
+ getOrCreateService() {
28
+ switch (this.config.accessoryType) {
29
+ case 'switch':
30
+ return this.accessory.getService(this.platform.Service.Switch)
31
+ ?? this.accessory.addService(this.platform.Service.Switch);
32
+ case 'outlet':
33
+ return this.accessory.getService(this.platform.Service.Outlet)
34
+ ?? this.accessory.addService(this.platform.Service.Outlet);
35
+ case 'fan':
36
+ return this.accessory.getService(this.platform.Service.Fan)
37
+ ?? this.accessory.addService(this.platform.Service.Fan);
38
+ case 'light':
39
+ default:
40
+ return this.accessory.getService(this.platform.Service.Lightbulb)
41
+ ?? this.accessory.addService(this.platform.Service.Lightbulb);
42
+ }
43
+ }
44
+ // A blaster has no feedback from the device it's controlling, so "On" is an
45
+ // assumed state we track ourselves rather than something read back from hardware.
46
+ getOn() {
47
+ return Boolean(this.accessory.context.on);
48
+ }
49
+ async setOn(value) {
50
+ const on = Boolean(value);
51
+ const code = selectPowerCode(this.config, on);
52
+ try {
53
+ await this.platform.broadlinkClient.sendCode(this.ip, code);
54
+ this.accessory.context.on = on;
55
+ this.platform.log.info(`Sent ${on ? 'Power On' : 'Power Off'} to ${this.config.name}`);
56
+ }
57
+ catch (error) {
58
+ this.platform.log.error(`Failed to send code for "${this.config.name}": ${error.message}`);
59
+ const { HapStatusError, HAPStatus } = this.platform.api.hap;
60
+ throw new HapStatusError(-70402 /* HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
61
+ }
62
+ }
63
+ }
64
+ exports.BasicAccessory = BasicAccessory;
65
+ //# sourceMappingURL=basicAccessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"basicAccessory.js","sourceRoot":"","sources":["../../src/accessories/basicAccessory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { PlatformAccessory } from 'homebridge';
2
+ import type { BroadlinkRMBlasterPlatform } from '../platform';
3
+ import type { DimmerAccessoryConfig } from '../configTypes';
4
+ export interface ResolvedLevel {
5
+ percent: number;
6
+ code: string;
7
+ }
8
+ export declare function getEffectiveMaxPercent(config: DimmerAccessoryConfig): number;
9
+ export declare function remapToPhysicalPercent(requestedPercent: number, config: DimmerAccessoryConfig): number;
10
+ export declare function findNearestLevel(config: DimmerAccessoryConfig, physicalPercent: number): ResolvedLevel;
11
+ export declare function resolveBrightnessCode(config: DimmerAccessoryConfig, requestedPercent: number): ResolvedLevel;
12
+ export declare function resolvePowerOnLevel(config: DimmerAccessoryConfig, lastKnown?: ResolvedLevel): ResolvedLevel;
13
+ export declare class DimmerAccessory {
14
+ private readonly platform;
15
+ private readonly accessory;
16
+ private readonly config;
17
+ private readonly ip;
18
+ private brightnessDebounceTimer?;
19
+ private brightnessActionId;
20
+ private lastSentCode?;
21
+ constructor(platform: BroadlinkRMBlasterPlatform, accessory: PlatformAccessory, config: DimmerAccessoryConfig, ip: string);
22
+ private getOn;
23
+ private getBrightness;
24
+ private clearBrightnessDebounce;
25
+ private turnOff;
26
+ private setOn;
27
+ private setBrightness;
28
+ private send;
29
+ }