homebridge-lanternic 0.1.3 → 0.2.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 +43 -6
- package/config.schema.json +115 -0
- package/dist/ble/magicLanternCommands.d.ts +1 -0
- package/dist/ble/magicLanternCommands.js +6 -0
- package/dist/ble/magicLanternCommands.js.map +1 -1
- package/dist/effects.d.ts +15 -0
- package/dist/effects.js +50 -0
- package/dist/effects.js.map +1 -0
- package/dist/platform.d.ts +1 -0
- package/dist/platform.js +8 -4
- package/dist/platform.js.map +1 -1
- package/dist/platformAccessory.d.ts +7 -0
- package/dist/platformAccessory.js +78 -1
- package/dist/platformAccessory.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/package.json +1 -1
- package/tools/send.mjs +33 -11
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Homebridge LanternIC
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/homebridge-lanternic)
|
|
4
|
-
[](https://www.npmjs.com/package/homebridge-lanternic)
|
|
5
4
|
[](https://github.com/Gibsonmb71/homebridge-lanternic/actions/workflows/ci.yml)
|
|
6
5
|
[](https://www.npmjs.com/package/homebridge-lanternic)
|
|
7
6
|
[](https://homebridge.io/)
|
|
@@ -16,6 +15,7 @@ These unbranded Magic Lantern BLE strips ship with multiple firmware variants so
|
|
|
16
15
|
- HomeKit Lightbulb service
|
|
17
16
|
- On/off with RGB-black fallback plus optional native Magic Lantern power frames
|
|
18
17
|
- Brightness via RGB scaling by default, with optional native Magic Lantern brightness frames
|
|
18
|
+
- Optional HomeKit switches for Magic Lantern effects
|
|
19
19
|
- HomeKit on/off, brightness, and color control confirmed on a `MELK-OC21WCT31` strip
|
|
20
20
|
- Homebridge UI config schema
|
|
21
21
|
- BLE discovery with log snippets and optional auto-add
|
|
@@ -23,7 +23,7 @@ These unbranded Magic Lantern BLE strips ship with multiple firmware variants so
|
|
|
23
23
|
- Command-builder tests for the known Magic Lantern frames
|
|
24
24
|
- Package smoke tests against Homebridge 1 and 2 on Node.js 22 and 24 in CI
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Segment-level IC control is not supported yet.
|
|
27
27
|
|
|
28
28
|
## Install
|
|
29
29
|
|
|
@@ -40,6 +40,14 @@ npm install
|
|
|
40
40
|
npm run build
|
|
41
41
|
sudo hb-service link
|
|
42
42
|
```
|
|
43
|
+
> [!CAUTION]
|
|
44
|
+
>
|
|
45
|
+
> Only the following platforms are supported:
|
|
46
|
+
>
|
|
47
|
+
> - **macOS**
|
|
48
|
+
> - If using macOS, you'll need to give Node.js permission to use Bluetooth in **System Settings → Privacy & Security → Bluetooth**.
|
|
49
|
+
> - **Linux**
|
|
50
|
+
> - 64-bit, not tested on 32-bit systems
|
|
43
51
|
|
|
44
52
|
## Homebridge UI Setup
|
|
45
53
|
|
|
@@ -48,9 +56,11 @@ LanternIC supports Homebridge UI through `config.schema.json`.
|
|
|
48
56
|
1. Install the plugin.
|
|
49
57
|
2. Open Homebridge UI.
|
|
50
58
|
3. Go to Plugins, select LanternIC, then Settings.
|
|
51
|
-
4.
|
|
52
|
-
5.
|
|
53
|
-
6.
|
|
59
|
+
4. Choose `Auto Mode` for first setup, or `Manual Mode` if you already know your strip's Bluetooth address.
|
|
60
|
+
5. Save and restart Homebridge.
|
|
61
|
+
6. In Auto Mode, LanternIC scans and auto-adds matching first-run candidates. In Manual Mode, paste the address into the `Light Strips` list.
|
|
62
|
+
|
|
63
|
+
After at least one light strip is configured, the setup mode picker is hidden and the advanced Discovery/Bluetooth settings become available.
|
|
54
64
|
|
|
55
65
|
You can also use the local scanner:
|
|
56
66
|
|
|
@@ -68,7 +78,7 @@ LANTERNIC_SCAN_ALL=1 lanternic-scan
|
|
|
68
78
|
|
|
69
79
|
When working from this repository instead of a global install, use `npm run scan` in place of `lanternic-scan`.
|
|
70
80
|
|
|
71
|
-
`Auto
|
|
81
|
+
First-run `Auto Mode` can create HomeKit accessories automatically for matching BLE candidates. After setup, use the advanced `Auto-Add Discovered Devices` setting only when your filters are tight, because nearby BLE devices may advertise similar services.
|
|
72
82
|
|
|
73
83
|
## CLI Tools
|
|
74
84
|
|
|
@@ -79,6 +89,7 @@ lanternic-scan
|
|
|
79
89
|
lanternic-explore <address>
|
|
80
90
|
lanternic-send <address> rgb ff0000
|
|
81
91
|
lanternic-send <address> brightness 50
|
|
92
|
+
lanternic-send <address> effect 207 39
|
|
82
93
|
lanternic-send-sequence <address> 7e070503ff000010ef 7e07050300ff0010ef
|
|
83
94
|
lanternic-calibrate <address>
|
|
84
95
|
```
|
|
@@ -138,6 +149,7 @@ Start with discovery enabled and no devices:
|
|
|
138
149
|
{
|
|
139
150
|
"platform": "LanternIC",
|
|
140
151
|
"name": "LanternIC",
|
|
152
|
+
"setupMode": "auto",
|
|
141
153
|
"devices": [],
|
|
142
154
|
"discovery": {
|
|
143
155
|
"enabled": true,
|
|
@@ -195,6 +207,31 @@ Restart Homebridge and look for candidate device addresses in the logs. Then add
|
|
|
195
207
|
6. If colors are swapped, change `colorOrder`.
|
|
196
208
|
7. If Off leaves the strip visibly on, keep `powerMode` as `both` or try `rgbBlack`.
|
|
197
209
|
8. If brightness does not change, keep `brightnessMode` as `rgb`; if it double-dims, try `native`.
|
|
210
|
+
9. If effects are enabled, test one effect switch at a time. Turning an effect switch off should restore the saved HomeKit color.
|
|
211
|
+
|
|
212
|
+
## HomeKit Effects
|
|
213
|
+
|
|
214
|
+
Magic Lantern animation effects are exposed as optional `Switch` services on the same HomeKit accessory as the light. Apple Home does not provide a native effect picker for a `Lightbulb`, and custom effect characteristics usually do not appear in the Home app.
|
|
215
|
+
|
|
216
|
+
Effects are disabled by default. Enable them per strip:
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"effects": {
|
|
221
|
+
"enabled": true,
|
|
222
|
+
"defaultSpeed": 39,
|
|
223
|
+
"restoreColorOnDisable": true
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
When `effects.enabled` is true and no custom `items` list is provided, LanternIC creates these starter switches:
|
|
229
|
+
|
|
230
|
+
- AutoPlay: effect code `0`
|
|
231
|
+
- Magic Back: effect code `1`
|
|
232
|
+
- Yellow Marquee: effect code `207` (`0xcf`)
|
|
233
|
+
|
|
234
|
+
Only one effect switch is kept active at a time. Turning on an effect sends the speed frame followed by the effect frame. Turning off the active effect restores the saved HomeKit color and brightness when `restoreColorOnDisable` is true.
|
|
198
235
|
|
|
199
236
|
## Protocol Notes
|
|
200
237
|
|
package/config.schema.json
CHANGED
|
@@ -15,12 +15,38 @@
|
|
|
15
15
|
"type": "string",
|
|
16
16
|
"default": "LanternIC"
|
|
17
17
|
},
|
|
18
|
+
"setupMode": {
|
|
19
|
+
"title": "Setup Mode",
|
|
20
|
+
"type": "string",
|
|
21
|
+
"default": "auto",
|
|
22
|
+
"description": "Choose Auto Mode for first setup unless you already know your strip's Bluetooth address.",
|
|
23
|
+
"oneOf": [
|
|
24
|
+
{
|
|
25
|
+
"title": "Auto Mode",
|
|
26
|
+
"enum": [
|
|
27
|
+
"auto"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"title": "Manual Mode",
|
|
32
|
+
"enum": [
|
|
33
|
+
"manual"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"condition": {
|
|
38
|
+
"functionBody": "return !model.devices || model.devices.length === 0;"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
18
41
|
"devices": {
|
|
19
42
|
"title": "Light Strips",
|
|
20
43
|
"type": "array",
|
|
21
44
|
"buttonText": "Add Light Strip",
|
|
22
45
|
"default": [],
|
|
23
46
|
"description": "Use discovery logs or lanternic-scan to find Magic Lantern BLE device ids. On Linux this is usually the MAC address; on macOS it may be a long CoreBluetooth id.",
|
|
47
|
+
"condition": {
|
|
48
|
+
"functionBody": "return (model.devices && model.devices.length > 0) || model.setupMode === 'manual';"
|
|
49
|
+
},
|
|
24
50
|
"items": {
|
|
25
51
|
"type": "object",
|
|
26
52
|
"required": [
|
|
@@ -144,6 +170,89 @@
|
|
|
144
170
|
]
|
|
145
171
|
}
|
|
146
172
|
]
|
|
173
|
+
},
|
|
174
|
+
"effects": {
|
|
175
|
+
"title": "Effects",
|
|
176
|
+
"type": "object",
|
|
177
|
+
"additionalProperties": false,
|
|
178
|
+
"description": "Optional HomeKit switch services for Magic Lantern animation effects.",
|
|
179
|
+
"properties": {
|
|
180
|
+
"enabled": {
|
|
181
|
+
"title": "Expose Effect Switches",
|
|
182
|
+
"type": "boolean",
|
|
183
|
+
"default": false,
|
|
184
|
+
"description": "Add HomeKit switches for Magic Lantern effects on this strip. Turning an effect switch off restores the normal light color by default."
|
|
185
|
+
},
|
|
186
|
+
"defaultSpeed": {
|
|
187
|
+
"title": "Default Effect Speed",
|
|
188
|
+
"type": "integer",
|
|
189
|
+
"default": 39,
|
|
190
|
+
"minimum": 0,
|
|
191
|
+
"maximum": 100,
|
|
192
|
+
"description": "Speed frame value sent before effect frames. 0 is slowest, 100 is fastest."
|
|
193
|
+
},
|
|
194
|
+
"restoreColorOnDisable": {
|
|
195
|
+
"title": "Restore Color When Effect Turns Off",
|
|
196
|
+
"type": "boolean",
|
|
197
|
+
"default": true,
|
|
198
|
+
"description": "When an active effect switch is turned off, send the saved HomeKit color and brightness back to the strip."
|
|
199
|
+
},
|
|
200
|
+
"items": {
|
|
201
|
+
"title": "Effect Switches",
|
|
202
|
+
"type": "array",
|
|
203
|
+
"buttonText": "Add Effect",
|
|
204
|
+
"default": [
|
|
205
|
+
{
|
|
206
|
+
"name": "AutoPlay",
|
|
207
|
+
"code": 0
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"name": "Magic Back",
|
|
211
|
+
"code": 1
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"name": "Yellow Marquee",
|
|
215
|
+
"code": 207
|
|
216
|
+
}
|
|
217
|
+
],
|
|
218
|
+
"description": "Effect codes are the xx byte in 7e0503xx06ffff00ef. Codes may be decimal, so Yellow Marquee is 207 for hex CF.",
|
|
219
|
+
"items": {
|
|
220
|
+
"type": "object",
|
|
221
|
+
"required": [
|
|
222
|
+
"name",
|
|
223
|
+
"code"
|
|
224
|
+
],
|
|
225
|
+
"additionalProperties": false,
|
|
226
|
+
"properties": {
|
|
227
|
+
"name": {
|
|
228
|
+
"title": "Name",
|
|
229
|
+
"type": "string",
|
|
230
|
+
"default": "Effect"
|
|
231
|
+
},
|
|
232
|
+
"code": {
|
|
233
|
+
"title": "Effect Code",
|
|
234
|
+
"type": "integer",
|
|
235
|
+
"default": 0,
|
|
236
|
+
"minimum": 0,
|
|
237
|
+
"maximum": 255,
|
|
238
|
+
"description": "Decimal value for the effect byte. For example hex CF is decimal 207."
|
|
239
|
+
},
|
|
240
|
+
"id": {
|
|
241
|
+
"title": "Stable Id",
|
|
242
|
+
"type": "string",
|
|
243
|
+
"description": "Optional stable HomeKit service id. Leave blank unless you are renaming or reordering effects and want to preserve existing HomeKit tiles."
|
|
244
|
+
},
|
|
245
|
+
"speed": {
|
|
246
|
+
"title": "Effect Speed Override",
|
|
247
|
+
"type": "integer",
|
|
248
|
+
"minimum": 0,
|
|
249
|
+
"maximum": 100,
|
|
250
|
+
"description": "Optional speed override for this effect. Leave blank to use Default Effect Speed."
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
147
256
|
}
|
|
148
257
|
}
|
|
149
258
|
}
|
|
@@ -152,6 +261,9 @@
|
|
|
152
261
|
"title": "Discovery",
|
|
153
262
|
"type": "object",
|
|
154
263
|
"additionalProperties": false,
|
|
264
|
+
"condition": {
|
|
265
|
+
"functionBody": "return model.devices && model.devices.length > 0;"
|
|
266
|
+
},
|
|
155
267
|
"properties": {
|
|
156
268
|
"enabled": {
|
|
157
269
|
"title": "Log Discovered Candidate Devices",
|
|
@@ -211,6 +323,9 @@
|
|
|
211
323
|
"title": "Bluetooth",
|
|
212
324
|
"type": "object",
|
|
213
325
|
"additionalProperties": false,
|
|
326
|
+
"condition": {
|
|
327
|
+
"functionBody": "return model.devices && model.devices.length > 0;"
|
|
328
|
+
},
|
|
214
329
|
"properties": {
|
|
215
330
|
"binding": {
|
|
216
331
|
"title": "Noble Binding",
|
|
@@ -14,3 +14,4 @@ export declare const buildPowerOnPrefixCommands: (powerMode?: PowerMode, brightn
|
|
|
14
14
|
export declare const buildPowerOffCommands: (powerMode?: PowerMode) => Buffer[];
|
|
15
15
|
export declare const buildEffectSpeedCommand: (speed: number) => Buffer;
|
|
16
16
|
export declare const buildBasicEffectCommand: (effectCode: number) => Buffer;
|
|
17
|
+
export declare const buildBasicEffectCommands: (effectCode: number, speed: number) => Buffer[];
|
|
@@ -46,4 +46,10 @@ export const buildEffectSpeedCommand = (speed) => {
|
|
|
46
46
|
export const buildBasicEffectCommand = (effectCode) => {
|
|
47
47
|
return frame(0x7e, 0x05, 0x03, effectCode, 0x06, 0xff, 0xff, 0x00, 0xef);
|
|
48
48
|
};
|
|
49
|
+
export const buildBasicEffectCommands = (effectCode, speed) => {
|
|
50
|
+
return [
|
|
51
|
+
buildEffectSpeedCommand(speed),
|
|
52
|
+
buildBasicEffectCommand(effectCode),
|
|
53
|
+
];
|
|
54
|
+
};
|
|
49
55
|
//# sourceMappingURL=magicLanternCommands.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"magicLanternCommands.js","sourceRoot":"","sources":["../../src/ble/magicLanternCommands.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"magicLanternCommands.js","sourceRoot":"","sources":["../../src/ble/magicLanternCommands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { LanternIcEffectConfig, LanternIcEffectsConfig } from './types.js';
|
|
2
|
+
export declare const EFFECT_SERVICE_SUBTYPE_PREFIX = "lanternic-effect-";
|
|
3
|
+
export interface ResolvedLanternIcEffect {
|
|
4
|
+
name: string;
|
|
5
|
+
code: number;
|
|
6
|
+
speed: number;
|
|
7
|
+
subtype: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ResolvedLanternIcEffectsConfig {
|
|
10
|
+
effects: ResolvedLanternIcEffect[];
|
|
11
|
+
restoreColorOnDisable: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare const DEFAULT_EFFECT_SPEED = 39;
|
|
14
|
+
export declare const DEFAULT_EFFECTS: LanternIcEffectConfig[];
|
|
15
|
+
export declare const resolveEffectsConfig: (config: LanternIcEffectsConfig | undefined) => ResolvedLanternIcEffectsConfig;
|
package/dist/effects.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { clampByte, clampPercent } from './color.js';
|
|
2
|
+
export const EFFECT_SERVICE_SUBTYPE_PREFIX = 'lanternic-effect-';
|
|
3
|
+
export const DEFAULT_EFFECT_SPEED = 39;
|
|
4
|
+
export const DEFAULT_EFFECTS = [
|
|
5
|
+
{ name: 'AutoPlay', code: 0 },
|
|
6
|
+
{ name: 'Magic Back', code: 1 },
|
|
7
|
+
{ name: 'Yellow Marquee', code: 0xcf },
|
|
8
|
+
];
|
|
9
|
+
const slugify = (value) => {
|
|
10
|
+
return value
|
|
11
|
+
.trim()
|
|
12
|
+
.toLowerCase()
|
|
13
|
+
.replace(/[^a-z0-9_-]+/g, '-')
|
|
14
|
+
.replace(/^-+|-+$/g, '')
|
|
15
|
+
.slice(0, 48);
|
|
16
|
+
};
|
|
17
|
+
export const resolveEffectsConfig = (config) => {
|
|
18
|
+
if (config?.enabled !== true) {
|
|
19
|
+
return {
|
|
20
|
+
effects: [],
|
|
21
|
+
restoreColorOnDisable: config?.restoreColorOnDisable ?? true,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const defaultSpeed = clampPercent(config.defaultSpeed ?? DEFAULT_EFFECT_SPEED);
|
|
25
|
+
const usedSubtypes = new Set();
|
|
26
|
+
const effects = (config.items?.length ? config.items : DEFAULT_EFFECTS)
|
|
27
|
+
.filter(effect => typeof effect.name === 'string' && effect.name.trim().length > 0)
|
|
28
|
+
.map((effect) => {
|
|
29
|
+
const code = clampByte(effect.code);
|
|
30
|
+
const baseId = slugify(effect.id ?? `${effect.name}-${code}`) || `effect-${code}`;
|
|
31
|
+
let subtype = `${EFFECT_SERVICE_SUBTYPE_PREFIX}${baseId}`;
|
|
32
|
+
let suffix = 2;
|
|
33
|
+
while (usedSubtypes.has(subtype)) {
|
|
34
|
+
subtype = `${EFFECT_SERVICE_SUBTYPE_PREFIX}${baseId}-${suffix}`;
|
|
35
|
+
suffix += 1;
|
|
36
|
+
}
|
|
37
|
+
usedSubtypes.add(subtype);
|
|
38
|
+
return {
|
|
39
|
+
name: effect.name,
|
|
40
|
+
code,
|
|
41
|
+
speed: clampPercent(effect.speed ?? defaultSpeed),
|
|
42
|
+
subtype,
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
effects,
|
|
47
|
+
restoreColorOnDisable: config.restoreColorOnDisable ?? true,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=effects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effects.js","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGrD,MAAM,CAAC,MAAM,6BAA6B,GAAG,mBAAmB,CAAC;AAcjE,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEvC,MAAM,CAAC,MAAM,eAAe,GAA4B;IACtD,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE;IAC7B,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,EAAE;IAC/B,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,IAAI,EAAE;CACvC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,KAAa,EAAU,EAAE;IACxC,OAAO,KAAK;SACT,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC;SAC7B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,MAA0C,EACV,EAAE;IAClC,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;QAC7B,OAAO;YACL,OAAO,EAAE,EAAE;YACX,qBAAqB,EAAE,MAAM,EAAE,qBAAqB,IAAI,IAAI;SAC7D,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,YAAY,IAAI,oBAAoB,CAAC,CAAC;IAC/E,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IAEvC,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC;SACpE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;SAClF,GAAG,CAAC,CAAC,MAAM,EAA2B,EAAE;QACvC,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,IAAI,UAAU,IAAI,EAAE,CAAC;QAClF,IAAI,OAAO,GAAG,GAAG,6BAA6B,GAAG,MAAM,EAAE,CAAC;QAC1D,IAAI,MAAM,GAAG,CAAC,CAAC;QAEf,OAAO,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACjC,OAAO,GAAG,GAAG,6BAA6B,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;YAChE,MAAM,IAAI,CAAC,CAAC;QACd,CAAC;QAED,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAE1B,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,IAAI;YACJ,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,KAAK,IAAI,YAAY,CAAC;YACjD,OAAO;SACR,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,OAAO;QACL,OAAO;QACP,qBAAqB,EAAE,MAAM,CAAC,qBAAqB,IAAI,IAAI;KAC5D,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/platform.d.ts
CHANGED
package/dist/platform.js
CHANGED
|
@@ -39,7 +39,7 @@ export class LanternIcPlatform {
|
|
|
39
39
|
if (activeUuids.has(uuid)) {
|
|
40
40
|
continue;
|
|
41
41
|
}
|
|
42
|
-
if (this.discoveryAutoAdd() && accessory.context.autoDiscovered) {
|
|
42
|
+
if (this.discoveryAutoAdd(devices) && accessory.context.autoDiscovered) {
|
|
43
43
|
const reason = discoverySucceeded ? 'it was previously auto-discovered' : 'discovery scan failed';
|
|
44
44
|
this.log.info(`Keeping cached auto-discovered accessory because ${reason}:`, accessory.displayName);
|
|
45
45
|
continue;
|
|
@@ -97,7 +97,7 @@ export class LanternIcPlatform {
|
|
|
97
97
|
}
|
|
98
98
|
for (const candidate of candidates) {
|
|
99
99
|
this.logCandidate(candidate);
|
|
100
|
-
if (!this.discoveryAutoAdd() || this.isConfigured(candidate, configuredDevices)) {
|
|
100
|
+
if (!this.discoveryAutoAdd(configuredDevices) || this.isConfigured(candidate, configuredDevices)) {
|
|
101
101
|
continue;
|
|
102
102
|
}
|
|
103
103
|
const device = this.deviceFromCandidate(candidate);
|
|
@@ -130,8 +130,12 @@ export class LanternIcPlatform {
|
|
|
130
130
|
const candidateId = normalizeBluetoothId(candidate.address || candidate.id);
|
|
131
131
|
return devices.some(device => normalizeBluetoothId(device.address) === candidateId);
|
|
132
132
|
}
|
|
133
|
-
discoveryAutoAdd() {
|
|
134
|
-
return this.config.discovery?.autoAdd === true
|
|
133
|
+
discoveryAutoAdd(configuredDevices) {
|
|
134
|
+
return this.config.discovery?.autoAdd === true
|
|
135
|
+
|| (this.firstSetupAutoMode() && configuredDevices.length === 0);
|
|
136
|
+
}
|
|
137
|
+
firstSetupAutoMode() {
|
|
138
|
+
return this.config.setupMode !== 'manual';
|
|
135
139
|
}
|
|
136
140
|
validDevices() {
|
|
137
141
|
const devices = this.config.devices ?? [];
|
package/dist/platform.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,sBAAsB,EAAwB,MAAM,iCAAiC,CAAC;AAC/F,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE3D,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEnF,MAAM,OAAO,iBAAiB;IAQV;IACA;IACA;IATF,OAAO,CAAiB;IACxB,cAAc,CAAwB;IACtC,GAAG,CAAyB;IAE3B,WAAW,GAAG,IAAI,GAAG,EAAwD,CAAC;IAE/F,YACkB,GAAY,EACZ,MAA+B,EAC/B,GAAQ;QAFR,QAAG,GAAH,GAAG,CAAS;QACZ,WAAM,GAAN,MAAM,CAAyB;QAC/B,QAAG,GAAH,GAAG,CAAK;QAExB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QAC7C,IAAI,CAAC,GAAG,GAAG,IAAI,sBAAsB,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;QAEvD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;YACrC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAC/C,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;gBACzC,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,yBAAyB,EACzB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB,CAAC,SAAuD;QACxE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,+BAA+B,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;QACtE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;IAEO,KAAK,CAAC,gBAAgB;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACpC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;QAEtC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAErF,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACjD,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,SAAS;YACX,CAAC;YAED,IAAI,IAAI,CAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,8 @@ export declare class LanternIcPlatformAccessory {
|
|
|
7
7
|
private readonly client;
|
|
8
8
|
private readonly accessory;
|
|
9
9
|
private readonly service;
|
|
10
|
+
private readonly effectSettings;
|
|
11
|
+
private readonly effectServices;
|
|
10
12
|
private readonly state;
|
|
11
13
|
private colorTimer?;
|
|
12
14
|
private colorWriteWaiters;
|
|
@@ -19,8 +21,13 @@ export declare class LanternIcPlatformAccessory {
|
|
|
19
21
|
private buildCurrentColorCommand;
|
|
20
22
|
private buildPowerOnCommands;
|
|
21
23
|
private buildBrightnessUpdateCommands;
|
|
24
|
+
private buildEffectCommands;
|
|
22
25
|
private powerMode;
|
|
23
26
|
private brightnessMode;
|
|
27
|
+
private configureEffectServices;
|
|
28
|
+
private setEffectSwitch;
|
|
29
|
+
private updateEffectSwitches;
|
|
30
|
+
private findEffect;
|
|
24
31
|
private resyncAfterReconnect;
|
|
25
32
|
private saveState;
|
|
26
33
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { applyColorOrder, clampPercent, hsbToRgb } from './color.js';
|
|
2
|
-
import { buildColorCommand, buildNativeBrightnessCommands, buildPowerOffCommands, buildPowerOnPrefixCommands, shouldScaleRgbBrightness, } from './ble/magicLanternCommands.js';
|
|
2
|
+
import { buildBasicEffectCommands, buildColorCommand, buildNativeBrightnessCommands, buildPowerOffCommands, buildPowerOnPrefixCommands, shouldScaleRgbBrightness, } from './ble/magicLanternCommands.js';
|
|
3
|
+
import { EFFECT_SERVICE_SUBTYPE_PREFIX, resolveEffectsConfig, } from './effects.js';
|
|
3
4
|
export class LanternIcPlatformAccessory {
|
|
4
5
|
platform;
|
|
5
6
|
device;
|
|
6
7
|
client;
|
|
7
8
|
accessory;
|
|
8
9
|
service;
|
|
10
|
+
effectSettings;
|
|
11
|
+
effectServices = new Map();
|
|
9
12
|
state;
|
|
10
13
|
colorTimer;
|
|
11
14
|
colorWriteWaiters = [];
|
|
@@ -22,7 +25,12 @@ export class LanternIcPlatformAccessory {
|
|
|
22
25
|
brightness: accessory.context.state?.brightness ?? 100,
|
|
23
26
|
hue: accessory.context.state?.hue ?? 0,
|
|
24
27
|
saturation: accessory.context.state?.saturation ?? 0,
|
|
28
|
+
activeEffect: accessory.context.state?.activeEffect,
|
|
25
29
|
};
|
|
30
|
+
this.effectSettings = resolveEffectsConfig(this.device.effects);
|
|
31
|
+
if (this.state.activeEffect && !this.findEffect(this.state.activeEffect)) {
|
|
32
|
+
this.state.activeEffect = undefined;
|
|
33
|
+
}
|
|
26
34
|
const informationService = accessory.getService(this.platform.Service.AccessoryInformation)
|
|
27
35
|
?? accessory.addService(this.platform.Service.AccessoryInformation);
|
|
28
36
|
informationService
|
|
@@ -44,12 +52,15 @@ export class LanternIcPlatformAccessory {
|
|
|
44
52
|
this.service.getCharacteristic(this.platform.Characteristic.Saturation)
|
|
45
53
|
.onGet(() => this.state.saturation)
|
|
46
54
|
.onSet(value => this.setSaturation(Number(value)));
|
|
55
|
+
this.configureEffectServices();
|
|
47
56
|
this.client.onReconnect(() => this.resyncAfterReconnect());
|
|
48
57
|
this.client.start();
|
|
49
58
|
}
|
|
50
59
|
async setOn(onValue) {
|
|
51
60
|
this.state.on = onValue;
|
|
61
|
+
this.state.activeEffect = undefined;
|
|
52
62
|
this.saveState();
|
|
63
|
+
this.updateEffectSwitches();
|
|
53
64
|
if (!onValue) {
|
|
54
65
|
await this.client.writeCommands(buildPowerOffCommands(this.powerMode()));
|
|
55
66
|
return;
|
|
@@ -58,7 +69,9 @@ export class LanternIcPlatformAccessory {
|
|
|
58
69
|
}
|
|
59
70
|
async setBrightness(value) {
|
|
60
71
|
this.state.brightness = clampPercent(Number(value));
|
|
72
|
+
this.state.activeEffect = undefined;
|
|
61
73
|
this.saveState();
|
|
74
|
+
this.updateEffectSwitches();
|
|
62
75
|
if (!this.state.on) {
|
|
63
76
|
return;
|
|
64
77
|
}
|
|
@@ -66,12 +79,16 @@ export class LanternIcPlatformAccessory {
|
|
|
66
79
|
}
|
|
67
80
|
async setHue(value) {
|
|
68
81
|
this.state.hue = Number(value);
|
|
82
|
+
this.state.activeEffect = undefined;
|
|
69
83
|
this.saveState();
|
|
84
|
+
this.updateEffectSwitches();
|
|
70
85
|
await this.scheduleColorWrite();
|
|
71
86
|
}
|
|
72
87
|
async setSaturation(value) {
|
|
73
88
|
this.state.saturation = clampPercent(Number(value));
|
|
89
|
+
this.state.activeEffect = undefined;
|
|
74
90
|
this.saveState();
|
|
91
|
+
this.updateEffectSwitches();
|
|
75
92
|
await this.scheduleColorWrite();
|
|
76
93
|
}
|
|
77
94
|
async scheduleColorWrite() {
|
|
@@ -118,17 +135,77 @@ export class LanternIcPlatformAccessory {
|
|
|
118
135
|
...(shouldScaleRgbBrightness(this.brightnessMode()) ? [this.buildCurrentColorCommand()] : []),
|
|
119
136
|
];
|
|
120
137
|
}
|
|
138
|
+
buildEffectCommands(effect) {
|
|
139
|
+
return [
|
|
140
|
+
...buildPowerOnPrefixCommands(this.powerMode(), this.brightnessMode(), this.state.brightness),
|
|
141
|
+
...buildBasicEffectCommands(effect.code, effect.speed),
|
|
142
|
+
];
|
|
143
|
+
}
|
|
121
144
|
powerMode() {
|
|
122
145
|
return this.device.powerMode ?? 'both';
|
|
123
146
|
}
|
|
124
147
|
brightnessMode() {
|
|
125
148
|
return this.device.brightnessMode ?? 'rgb';
|
|
126
149
|
}
|
|
150
|
+
configureEffectServices() {
|
|
151
|
+
const wantedSubtypes = new Set(this.effectSettings.effects.map(effect => effect.subtype));
|
|
152
|
+
for (const existingService of [...this.accessory.services]) {
|
|
153
|
+
if (existingService.UUID === this.platform.Service.Switch.UUID
|
|
154
|
+
&& existingService.subtype?.startsWith(EFFECT_SERVICE_SUBTYPE_PREFIX)
|
|
155
|
+
&& !wantedSubtypes.has(existingService.subtype)) {
|
|
156
|
+
this.accessory.removeService(existingService);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
for (const effect of this.effectSettings.effects) {
|
|
160
|
+
const service = this.accessory.getServiceById(this.platform.Service.Switch, effect.subtype)
|
|
161
|
+
?? this.accessory.addService(this.platform.Service.Switch, effect.name, effect.subtype);
|
|
162
|
+
service.setCharacteristic(this.platform.Characteristic.Name, effect.name);
|
|
163
|
+
service.getCharacteristic(this.platform.Characteristic.On)
|
|
164
|
+
.onGet(() => this.state.activeEffect === effect.subtype)
|
|
165
|
+
.onSet(value => this.setEffectSwitch(effect, Boolean(value)));
|
|
166
|
+
this.effectServices.set(effect.subtype, service);
|
|
167
|
+
}
|
|
168
|
+
this.updateEffectSwitches();
|
|
169
|
+
}
|
|
170
|
+
async setEffectSwitch(effect, onValue) {
|
|
171
|
+
if (!onValue) {
|
|
172
|
+
if (this.state.activeEffect !== effect.subtype) {
|
|
173
|
+
this.updateEffectSwitches();
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
this.state.activeEffect = undefined;
|
|
177
|
+
this.saveState();
|
|
178
|
+
this.updateEffectSwitches();
|
|
179
|
+
if (this.effectSettings.restoreColorOnDisable && this.state.on) {
|
|
180
|
+
await this.client.writeCommands(this.buildPowerOnCommands());
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
this.state.on = true;
|
|
185
|
+
this.state.activeEffect = effect.subtype;
|
|
186
|
+
this.saveState();
|
|
187
|
+
this.service.updateCharacteristic(this.platform.Characteristic.On, true);
|
|
188
|
+
this.updateEffectSwitches();
|
|
189
|
+
await this.client.writeCommands(this.buildEffectCommands(effect));
|
|
190
|
+
}
|
|
191
|
+
updateEffectSwitches() {
|
|
192
|
+
for (const [subtype, service] of this.effectServices) {
|
|
193
|
+
service.updateCharacteristic(this.platform.Characteristic.On, this.state.activeEffect === subtype);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
findEffect(subtype) {
|
|
197
|
+
return this.effectSettings.effects.find(effect => effect.subtype === subtype);
|
|
198
|
+
}
|
|
127
199
|
async resyncAfterReconnect() {
|
|
128
200
|
if (!this.state.on) {
|
|
129
201
|
return;
|
|
130
202
|
}
|
|
131
203
|
this.platform.log.debug(`[${this.device.name}] Resyncing desired state after BLE reconnect`);
|
|
204
|
+
const activeEffect = this.findEffect(this.state.activeEffect);
|
|
205
|
+
if (activeEffect) {
|
|
206
|
+
await this.client.writeCommands(this.buildEffectCommands(activeEffect));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
132
209
|
await this.client.writeCommands(this.buildPowerOnCommands());
|
|
133
210
|
}
|
|
134
211
|
saveState() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platformAccessory.js","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAErE,OAAO,EACL,iBAAiB,EACjB,6BAA6B,EAC7B,qBAAqB,EACrB,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"platformAccessory.js","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,19 @@ export type BrightnessMode = 'rgb' | 'native' | 'both';
|
|
|
5
5
|
export type NobleBinding = 'default' | 'hci' | 'mac' | 'win';
|
|
6
6
|
export type HciDriver = 'default' | 'native' | 'usb' | 'uart';
|
|
7
7
|
export type WriteMode = 'auto' | 'withResponse' | 'withoutResponse';
|
|
8
|
+
export type SetupMode = 'auto' | 'manual';
|
|
9
|
+
export interface LanternIcEffectConfig {
|
|
10
|
+
name: string;
|
|
11
|
+
code: number;
|
|
12
|
+
id?: string;
|
|
13
|
+
speed?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface LanternIcEffectsConfig {
|
|
16
|
+
enabled?: boolean;
|
|
17
|
+
defaultSpeed?: number;
|
|
18
|
+
restoreColorOnDisable?: boolean;
|
|
19
|
+
items?: LanternIcEffectConfig[];
|
|
20
|
+
}
|
|
8
21
|
export interface LanternIcDeviceConfig {
|
|
9
22
|
name: string;
|
|
10
23
|
address: string;
|
|
@@ -13,6 +26,7 @@ export interface LanternIcDeviceConfig {
|
|
|
13
26
|
colorOrder?: ColorOrder;
|
|
14
27
|
powerMode?: PowerMode;
|
|
15
28
|
brightnessMode?: BrightnessMode;
|
|
29
|
+
effects?: LanternIcEffectsConfig;
|
|
16
30
|
}
|
|
17
31
|
export interface LanternIcDiscoveryConfig {
|
|
18
32
|
enabled?: boolean;
|
|
@@ -45,6 +59,7 @@ export interface LanternIcBleConfig {
|
|
|
45
59
|
}
|
|
46
60
|
export interface LanternIcPlatformConfig extends PlatformConfig {
|
|
47
61
|
name?: string;
|
|
62
|
+
setupMode?: SetupMode;
|
|
48
63
|
devices?: LanternIcDeviceConfig[];
|
|
49
64
|
discovery?: LanternIcDiscoveryConfig;
|
|
50
65
|
ble?: LanternIcBleConfig;
|
|
@@ -54,6 +69,7 @@ export interface LanternIcStoredState {
|
|
|
54
69
|
brightness?: number;
|
|
55
70
|
hue?: number;
|
|
56
71
|
saturation?: number;
|
|
72
|
+
activeEffect?: string;
|
|
57
73
|
}
|
|
58
74
|
export interface LanternIcAccessoryContext {
|
|
59
75
|
autoDiscovered?: boolean;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "homebridge-lanternic",
|
|
3
3
|
"displayName": "LanternIC",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.2.0",
|
|
6
6
|
"description": "Homebridge plugin for BLE RGBIC/RGBWIC light strips controlled by the Magic Lantern app.",
|
|
7
7
|
"author": "Gibson Bell",
|
|
8
8
|
"license": "MIT",
|
package/tools/send.mjs
CHANGED
|
@@ -4,16 +4,20 @@ import { withBindings } from '@stoprocent/noble';
|
|
|
4
4
|
const binding = process.env.LANTERNIC_BINDING ?? 'default';
|
|
5
5
|
const serviceUuid = (process.env.LANTERNIC_SERVICE_UUID ?? 'fff0').replace(/[^0-9a-f]/gi, '').toLowerCase();
|
|
6
6
|
const characteristicUuid = (process.env.LANTERNIC_CHARACTERISTIC_UUID ?? 'fff3').replace(/[^0-9a-f]/gi, '').toLowerCase();
|
|
7
|
+
const delayMs = Number(process.env.LANTERNIC_WRITE_DELAY_MS ?? 120);
|
|
7
8
|
const address = process.argv[2];
|
|
8
9
|
const command = process.argv[3];
|
|
9
10
|
const value = process.argv[4];
|
|
11
|
+
const extraValue = process.argv[5];
|
|
10
12
|
|
|
11
13
|
if (!address || !command) {
|
|
12
|
-
console.error('Usage: lanternic-send <address> <on|off|brightness|rgb|raw> [value]');
|
|
13
|
-
console.error('Repo development: npm run send -- <address> <on|off|brightness|rgb|raw> [value]');
|
|
14
|
+
console.error('Usage: lanternic-send <address> <on|off|brightness|speed|effect|rgb|raw> [value] [speed]');
|
|
15
|
+
console.error('Repo development: npm run send -- <address> <on|off|brightness|speed|effect|rgb|raw> [value] [speed]');
|
|
14
16
|
console.error('Examples:');
|
|
15
17
|
console.error(' lanternic-send be:16:70:00:08:2a on');
|
|
16
18
|
console.error(' lanternic-send be:16:70:00:08:2a brightness 50');
|
|
19
|
+
console.error(' lanternic-send be:16:70:00:08:2a speed 39');
|
|
20
|
+
console.error(' lanternic-send be:16:70:00:08:2a effect 207 39');
|
|
17
21
|
console.error(' lanternic-send be:16:70:00:08:2a rgb ff0000');
|
|
18
22
|
console.error(' lanternic-send be:16:70:00:08:2a raw 7e0404f00001ff00ef');
|
|
19
23
|
process.exit(2);
|
|
@@ -27,18 +31,33 @@ const noble = withBindings(binding);
|
|
|
27
31
|
const byte = number => Math.max(0, Math.min(255, Math.round(number)));
|
|
28
32
|
const percent = number => Math.max(0, Math.min(100, Math.round(number)));
|
|
29
33
|
const frame = (...bytes) => Buffer.from(bytes.map(byte));
|
|
34
|
+
const wait = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
30
35
|
|
|
31
|
-
const
|
|
36
|
+
const buildPayloads = () => {
|
|
32
37
|
if (command === 'on') {
|
|
33
|
-
return Buffer.from('7e0404f00001ff00ef', 'hex');
|
|
38
|
+
return [Buffer.from('7e0404f00001ff00ef', 'hex')];
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
if (command === 'off') {
|
|
37
|
-
return Buffer.from('7e0404000000ff00ef', 'hex');
|
|
42
|
+
return [Buffer.from('7e0404000000ff00ef', 'hex')];
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
if (command === 'brightness') {
|
|
41
|
-
return frame(0x7e, 0x04, 0x01, percent(Number(value)), 0x01, 0xff, 0xff, 0x00, 0xef);
|
|
46
|
+
return [frame(0x7e, 0x04, 0x01, percent(Number(value)), 0x01, 0xff, 0xff, 0x00, 0xef)];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (command === 'speed') {
|
|
50
|
+
return [frame(0x7e, 0x04, 0x02, percent(Number(value)), 0xff, 0xff, 0xff, 0x00, 0xef)];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (command === 'effect') {
|
|
54
|
+
const payloads = [];
|
|
55
|
+
if (extraValue !== undefined) {
|
|
56
|
+
payloads.push(frame(0x7e, 0x04, 0x02, percent(Number(extraValue)), 0xff, 0xff, 0xff, 0x00, 0xef));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
payloads.push(frame(0x7e, 0x05, 0x03, byte(Number(value)), 0x06, 0xff, 0xff, 0x00, 0xef));
|
|
60
|
+
return payloads;
|
|
42
61
|
}
|
|
43
62
|
|
|
44
63
|
if (command === 'rgb') {
|
|
@@ -46,18 +65,18 @@ const buildPayload = () => {
|
|
|
46
65
|
if (rgb.length !== 6) {
|
|
47
66
|
throw new Error('rgb value must be RRGGBB hex, for example ff0000');
|
|
48
67
|
}
|
|
49
|
-
return Buffer.from(`7e070503${rgb}10ef`, 'hex');
|
|
68
|
+
return [Buffer.from(`7e070503${rgb}10ef`, 'hex')];
|
|
50
69
|
}
|
|
51
70
|
|
|
52
71
|
if (command === 'raw') {
|
|
53
|
-
return Buffer.from(cleanId(value), 'hex');
|
|
72
|
+
return [Buffer.from(cleanId(value), 'hex')];
|
|
54
73
|
}
|
|
55
74
|
|
|
56
75
|
throw new Error(`Unknown command: ${command}`);
|
|
57
76
|
};
|
|
58
77
|
|
|
59
|
-
const
|
|
60
|
-
console.log(`Sending ${payload.toString('hex')} to ${address} with binding=${binding}`);
|
|
78
|
+
const payloads = buildPayloads();
|
|
79
|
+
console.log(`Sending ${payloads.map(payload => payload.toString('hex')).join(', ')} to ${address} with binding=${binding}`);
|
|
61
80
|
|
|
62
81
|
await noble.waitForPoweredOnAsync(15_000);
|
|
63
82
|
await noble.startScanningAsync([], true);
|
|
@@ -98,7 +117,10 @@ try {
|
|
|
98
117
|
|
|
99
118
|
const withoutResponse = !characteristic.properties.includes('write')
|
|
100
119
|
&& characteristic.properties.includes('writeWithoutResponse');
|
|
101
|
-
|
|
120
|
+
for (const payload of payloads) {
|
|
121
|
+
await characteristic.writeAsync(payload, withoutResponse);
|
|
122
|
+
await wait(delayMs);
|
|
123
|
+
}
|
|
102
124
|
console.log(`Write complete withoutResponse=${withoutResponse}`);
|
|
103
125
|
} finally {
|
|
104
126
|
await peripheral.disconnectAsync();
|