homebridge-dyson-solarcycle-morph 0.3.0 → 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/CHANGELOG.md CHANGED
@@ -5,6 +5,53 @@ All notable changes to this project are documented here.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.0] — 2026-09-18
9
+
10
+ Everything the lamp will tell us over Bluetooth is now in HomeKit, and the
11
+ protocol behind it is written down rather than inherited. Stable enough to call
12
+ it that.
13
+
14
+ ### Added
15
+
16
+ - **The lamp's preset modes, as switches.** Study, Relax and Precision apply a
17
+ set of values and spring back, the way a scene does. Turn them off per light
18
+ with `presetSwitches`.
19
+
20
+ ### Removed
21
+
22
+ - **The motion sensor.** It reported motion permanently. The characteristic it
23
+ read holds a constant on this lamp — it never changed across the lamp being
24
+ on, off, and movement mode being switched either way — so there was nothing
25
+ behind it, and anything automated on it would have fired forever. The lamp's
26
+ movement mode, which is what most people want it for, is a switch and works.
27
+
28
+ ### Fixed
29
+
30
+ - Every switch showed in the Home app under the accessory's own name, so a lamp
31
+ with three of them had three controls all called the same thing. They now
32
+ carry their own names.
33
+
34
+ ## [0.4.0] — 2026-09-18
35
+
36
+ ### Added
37
+
38
+ - **The lamp's Auto and movement switches reach HomeKit.** Auto brightness, where
39
+ the lamp trims its own output to keep the room level, and movement mode, where
40
+ it lights on movement and goes out once the room is still, are both switches
41
+ now. They show the true state and follow the buttons on the lamp itself. Turn
42
+ either off per light with `autoBrightnessSwitch` and `movementSwitch`.
43
+
44
+ ### Changed
45
+
46
+ - The README lists the three mode switches in one place, with the settings that
47
+ turn each off and how the Movement switch differs from the motion sensor.
48
+
49
+ ### Fixed
50
+
51
+ - The notes said the lamp trimmed brightness to track daylight from its location
52
+ and the time of day. Daylight mode moves colour temperature; what moves
53
+ brightness is auto brightness and the ramp towards a newly written value.
54
+
8
55
  ## [0.3.0] — 2026-09-18
9
56
 
10
57
  ### Added
package/README.md CHANGED
@@ -15,17 +15,43 @@
15
15
 
16
16
  ## What you get
17
17
 
18
- Your lamp appears in the Home app as a **light**, with the controls Apple provides for one:
18
+ Your lamp appears in the Home app as a **light**, with the controls Apple
19
+ provides for one:
19
20
 
20
21
  - **On and off**
21
22
  - **Brightness**
22
23
  - **Colour temperature**, across the lamp's full 2700–6500 K range
23
- - **Motion**, from the lamp's own sensor, as a separate sensor you can automate on
24
24
  - **Siri**: *"Hey Siri, turn on the desk light"*, *"Hey Siri, set the desk light to 50%"*
25
25
 
26
- After setup nothing leaves your home. The lamp has no Wi-Fi at all: the plugin
27
- talks to it over Bluetooth, and the one cloud request — fetching the lamp's key —
28
- happens once, during pairing.
26
+ Alongside it, the three modes that otherwise live only on the lamp's base or in
27
+ the MyDyson app — each a switch you can automate on, and each showing what the
28
+ lamp is really doing rather than what was last asked of it:
29
+
30
+ | switch | what it does |
31
+ | --- | --- |
32
+ | **Daylight** | shifts colour temperature through the day, warm in the evening and cool at midday |
33
+ | **Auto Brightness** | trims the level to suit the room as the light around it changes |
34
+ | **Movement** | lights when it sees movement, goes out once the room has been still |
35
+
36
+ Plus the lamp's three preset modes — **Study**, **Relax** and **Precision** — as
37
+ switches that apply a set of values and spring back, the way a scene does. They
38
+ are what the buttons in the MyDyson app do, and the lamp allows only one at a
39
+ time.
40
+
41
+ | preset | where it puts the lamp |
42
+ | --- | --- |
43
+ | Study | 4741 K, fairly bright |
44
+ | Relax | 2900 K, dim and warm |
45
+ | Precision | 4600 K, full output |
46
+
47
+ **It follows the lamp, not just the other way round.** Press a button on the
48
+ base, change something in the MyDyson app, or let the lamp end daylight tracking
49
+ by itself, and the Home app keeps up — usually within a second. A lamp that is
50
+ out of range says so, rather than showing you the last thing it knew.
51
+
52
+ **After setup nothing leaves your home.** The lamp has no Wi-Fi at all: the
53
+ plugin talks to it over Bluetooth, and the one cloud request — fetching the
54
+ lamp's key — happens once, during pairing.
29
55
 
30
56
  ## Before you start
31
57
 
@@ -34,7 +60,7 @@ happens once, during pairing.
34
60
  | **Lamp** | Dyson Solarcycle Morph or Lightcycle Morph, added to your MyDyson account |
35
61
  | **Homebridge** | 2.0.0 or newer, on Linux |
36
62
  | **Node.js** | 22.18, 24 or 26 |
37
- | **Range** | The Homebridge host must be within Bluetooth range of the lamp |
63
+ | **Range** | The Homebridge host must be within Bluetooth range of the lamp, and stay there — these lamps have no Wi-Fi, so there is no cloud fallback |
38
64
 
39
65
  **The lamp must already be in the MyDyson app.** This is not a formality. The
40
66
  lamp ignores every command until it is handed a key that only Dyson can issue,
@@ -42,8 +68,9 @@ against the account the lamp is registered to — there is no way to read it fro
42
68
  the device. If the lamp is not on your account, pairing returns a 404 and there
43
69
  is nothing the plugin can do about it.
44
70
 
45
- **Linux only.** The plugin talks to BlueZ over D-Bus, so macOS and Windows will
46
- not work. A Raspberry Pi running Homebridge is the usual home for it.
71
+ **Linux only.** macOS and Windows will not work, for Bluetooth reasons that are
72
+ not worth going into here. A Raspberry Pi running Homebridge is the usual home
73
+ for it.
47
74
 
48
75
  ## Step 1 — Install the plugin
49
76
 
@@ -73,40 +100,37 @@ Open the plugin's **Settings**. The page walks through it:
73
100
 
74
101
  Restart Homebridge when the page says so.
75
102
 
76
- ### What is stored, and where
77
-
78
- The lamp's key and your account session go into the plugin's own storage
79
- directory, not into `config.json`. The file you can open in the Homebridge UI —
80
- and paste into a support thread — holds nothing sensitive.
81
-
82
- Your password is only needed to exchange a code for a session. **Forget
83
- password** removes it afterwards; the lamp keeps working, because its key does
84
- not expire.
85
-
86
103
  ## Step 4 — Add the lamp to the Home app
87
104
 
88
105
  The child bridge has its own QR code, under **Bridge Settings**. Scan it in the
89
106
  Home app the same way you paired Homebridge itself.
90
107
 
91
- ## Everyday use
108
+ ## Using it
109
+
110
+ **Turning it on, dimming it, changing the colour** — all the usual Home app
111
+ controls, and Siri.
112
+
113
+ **The three switches can be automated like anything else.** A few that people
114
+ tend to want:
115
+
116
+ - Movement on when you leave for work, off when you get home
117
+ - Daylight on in the morning, so the lamp cools towards midday and warms again by evening on its own
118
+ - Auto Brightness off when you sit down to watch a film
92
119
 
93
- **Brightness will not always land exactly where you put it.** The lamp ramps
94
- towards a value rather than jumping, and trims it to track daylight from its
95
- location and the time of day. Asking for 100% and seeing 88% is the lamp working
96
- as designed.
120
+ **Brightness will not always land exactly where you put it.** The lamp eases
121
+ towards a new level rather than jumping, and with Auto Brightness on it keeps
122
+ adjusting to suit the room. Asking for 100% and seeing 88% is the lamp doing its
123
+ job — turn Auto Brightness off if you would rather it stayed put.
97
124
 
98
- **Changes made at the lamp show up in the Home app**, usually at once and at
99
- worst within a minute.
125
+ **Setting a colour temperature ends daylight tracking**, and the Daylight switch
126
+ turns itself off when you do. That is the lamp's own behaviour, not something
127
+ the plugin decides. Flip the switch back on to resume.
100
128
 
101
- **When the lamp is out of reach**, the Home app shows it as *No Response* rather
102
- than the last value it knew, and commands fail instead of being silently queued.
103
- The plugin reconnects on its own and reads the lamp's real state when it does.
129
+ **Changes made at the lamp appear in the Home app**, usually straight away.
104
130
 
105
- **Switching off is checked.** Control commands are unacknowledged, so one can be
106
- dropped in transit. Power is read back shortly after and resent if it did not
107
- take — a lamp still lit after being switched off is the one failure nobody can
108
- work around. Brightness and colour temperature are deliberately not checked,
109
- because the lamp adjusts them itself and a correction would fight it.
131
+ **Out of range, the lamp shows as *No Response*** rather than the last thing it
132
+ knew, and commands fail rather than being quietly dropped. It comes back on its
133
+ own once the link does.
110
134
 
111
135
  ## Settings
112
136
 
@@ -118,30 +142,51 @@ Everything except the lights is optional.
118
142
  | **Lights → Name** | What the lamp is called in the Home app |
119
143
  | **Lights → BLE MAC address** | Filled in by the scan |
120
144
  | **Lights → Serial number** | Filled in by the scan. Identifies the accessory, so changing it creates a new one |
121
- | **Lights → Expose the motion sensor** | Adds the lamp's motion detector as a HomeKit sensor |
145
+ | **Lights → Expose daylight tracking** | The Daylight switch. On by default |
146
+ | **Lights → Expose auto brightness** | The Auto Brightness switch. On by default |
147
+ | **Lights → Expose movement mode** | The Movement switch. On by default |
148
+ | **Lights → Expose the preset modes** | The Study, Relax and Precision switches. On by default |
122
149
  | **Bluetooth adapter** | Only needed if the host has more than one, e.g. `hci1` |
123
150
 
124
151
  ## If something goes wrong
125
152
 
126
153
  **The lamp shows as *No Response*.** There is no Bluetooth link at that moment.
127
- The plugin keeps reconnecting; if it does not recover, read on.
154
+ The plugin keeps trying; it usually sorts itself out.
155
+
156
+ **It never connects at all, however long you leave it.** Unplug the lamp for ten
157
+ seconds. Its Bluetooth can get into a state where it looks perfectly healthy but
158
+ refuses every connection, and a power cycle is the only thing that clears it.
159
+ The plugin will pick the lamp up again by itself afterwards.
160
+
161
+ **It connects, drops, reconnects, over and over.** Usually either the lamp is too
162
+ far from the Homebridge host, or something nearby is using the same airwaves —
163
+ Wi-Fi especially. [Reading the signal](#reading-the-signal) below shows which.
164
+
165
+ **It says the lamp is not paired yet.** No key is stored for that serial. Open
166
+ the plugin's settings and authorise your account again, and check the serial
167
+ matches the lamp exactly — that is what the key is filed under.
168
+
169
+ **Pairing returns a 404.** The lamp is not on that Dyson account. It has to be
170
+ added in the MyDyson app first; there is no way round this.
171
+
172
+ **A few failed attempts at startup are normal.** Connecting to this lamp works
173
+ about two times in three whatever anyone does, so the plugin simply tries again.
174
+ Only a cycle that never succeeds is worth looking at.
175
+
176
+ ## Under the hood
128
177
 
129
- **The log repeats `le-connection-abort-by-local` and never connects.** The lamp's
130
- Bluetooth stack can reach a state where it advertises perfectly well — a scan
131
- finds it, at a good signal strength — but refuses every connection.
132
- **Disconnecting the lamp from power for ten seconds clears it**, reliably.
133
- Nothing on the Homebridge side does. The plugin thins its attempts out to five
134
- minutes apart, so it will pick the lamp up again by itself once you have.
178
+ Not needed to use the plugin, but useful when something looks odd.
135
179
 
136
- **It connects, drops, reconnects, over and over.** Look at the signal line in the
137
- log:
180
+ ### Reading the signal
181
+
182
+ Once a minute the log carries a line like:
138
183
 
139
184
  ```
140
185
  Signal from F0:… : -73 dBm average, -80 to -67
141
186
  ```
142
187
 
143
- The **average** answers one question — is the lamp too far away. Around −60 dBm
144
- is comfortable, −75 workable, −85 will not hold.
188
+ The **average** answers one question: is the lamp too far away. Around −60 dBm is
189
+ comfortable, −75 workable, −85 will not hold.
145
190
 
146
191
  The **spread** answers a different one. A lamp that is not moving cannot swing by
147
192
  20 dB on its own, so a wide spread means something else is using the band. So do
@@ -154,41 +199,45 @@ which sits directly on a Bluetooth advertising channel. If the host is on
154
199
  Ethernet anyway, `sudo nmcli radio wifi off` settles it. Zigbee is worth checking
155
200
  next: channels 15, 20 and 25 sit in the gaps between Wi-Fi 1, 6 and 11.
156
201
 
157
- **`… is not paired yet`.** No key is stored for that serial. Open the plugin's
158
- settings and authorise your account. Check the serial matches the lamp exactly —
159
- it is what the key is filed under.
202
+ Moving the host closer is worth more than any of it. One measured move took a
203
+ link from −76 dBm with two drops an hour to −50 dBm with none.
204
+
205
+ ### Why switching off is double-checked
206
+
207
+ Commands to this lamp are unacknowledged: the plugin sends one and the lamp says
208
+ nothing back, so a command can be lost with nothing to show for it. Power is
209
+ therefore read back shortly after and resent if it did not take — a lamp still
210
+ lit after being switched off is the one failure nobody can work around.
211
+
212
+ Brightness and colour temperature are deliberately *not* checked, because the
213
+ lamp moves them itself and a correction would fight it.
214
+
215
+ ### What is stored, and where
216
+
217
+ The lamp's key and your account session go into the plugin's own storage
218
+ directory, not into `config.json`. The file you can open in the Homebridge UI —
219
+ and paste into a support thread — holds nothing sensitive.
220
+
221
+ Your password is only needed to exchange a code for a session. **Forget
222
+ password** removes it afterwards; the lamp keeps working, because its key does
223
+ not expire.
224
+
225
+ ### Setting up without the Homebridge UI
226
+
227
+ `dyson-morph-pair` does the same pairing from a terminal. See
228
+ [CONTRIBUTING.md](CONTRIBUTING.md).
229
+
230
+ ### Rarer errors
160
231
 
161
232
  **`PayloadB failed HMAC verification`.** The stored key is wrong or corrupted.
162
233
  Pair the lamp again.
163
234
 
164
- **404 when fetching the key.** The lamp is not registered to that Dyson account.
165
- See *Before you start*.
166
-
167
235
  **`Not authorized` from D-Bus.** Only on distributions that restrict BlueZ
168
236
  access — Debian and Raspberry Pi OS already allow it. If yours does not, create
169
237
  `/etc/dbus-1/system.d/node-ble.conf` with a policy for the user Homebridge runs
170
238
  as, then restart `dbus`. There is an example in
171
239
  [the node-ble documentation](https://github.com/chrvadala/node-ble#provide-permissions).
172
240
 
173
- ## Good to know
174
-
175
- **Bluetooth only.** These lamps have no Wi-Fi, so the Homebridge host has to be
176
- within range. There is no cloud fallback when it is not.
177
-
178
- **A few failed attempts at startup are normal.** Connecting to this lamp
179
- succeeds roughly two times in three, whatever you do, so the plugin simply tries
180
- several times in quick succession. Only a cycle that never succeeds is worth
181
- looking at.
182
-
183
- **Daylight tracking appears as its own switch.** It shows what the lamp is
184
- actually doing, following the button on the lamp's base and the MyDyson app as
185
- well as HomeKit. Setting a colour temperature ends the tracking — that is the
186
- lamp's own behaviour, not the plugin's — so the switch turns itself off when you
187
- do. Turn it off per light with `daylightSwitch` if you would rather not have it.
188
-
189
- **Setup without the Homebridge UI.** `dyson-morph-pair` does the same pairing
190
- from a terminal. See [CONTRIBUTING.md](CONTRIBUTING.md).
191
-
192
241
  ## For developers
193
242
 
194
243
  The protocol, including where a real lamp disagreed with the published notes, is
@@ -45,11 +45,23 @@
45
45
  "required": true,
46
46
  "description": "Printed on the lamp base and shown in the MyDyson app."
47
47
  },
48
- "motionSensor": {
49
- "title": "Expose the motion sensor",
48
+ "autoBrightnessSwitch": {
49
+ "title": "Expose auto brightness",
50
50
  "type": "boolean",
51
- "default": false,
52
- "description": "Adds the lamp's built-in motion detector as a HomeKit motion sensor."
51
+ "default": true,
52
+ "description": "Adds a switch for the lamp's \"Auto\" setting, which trims brightness to keep the room at a steady level."
53
+ },
54
+ "movementSwitch": {
55
+ "title": "Expose movement mode",
56
+ "type": "boolean",
57
+ "default": true,
58
+ "description": "Adds a switch for the lamp's movement mode, where it lights on movement and goes out once the room has been still."
59
+ },
60
+ "presetSwitches": {
61
+ "title": "Expose the preset modes",
62
+ "type": "boolean",
63
+ "default": true,
64
+ "description": "Adds the lamp's Study, Relax and Precision modes as switches. Only one can be on at a time, which the lamp itself enforces."
53
65
  },
54
66
  "daylightSwitch": {
55
67
  "title": "Expose daylight tracking",
@@ -105,8 +117,10 @@
105
117
  "lights[].name",
106
118
  "lights[].mac",
107
119
  "lights[].serial",
108
- "lights[].motionSensor",
109
- "lights[].daylightSwitch"
120
+ "lights[].daylightSwitch",
121
+ "lights[].autoBrightnessSwitch",
122
+ "lights[].movementSwitch",
123
+ "lights[].presetSwitches"
110
124
  ]
111
125
  }
112
126
  ]
@@ -14,8 +14,10 @@ export declare class MorphAccessory {
14
14
  private readonly accessory;
15
15
  private readonly config;
16
16
  private readonly lightbulb;
17
- private readonly motion?;
18
17
  private readonly daylight?;
18
+ private readonly autoBrightness?;
19
+ private readonly movement?;
20
+ private readonly presets;
19
21
  private readonly lamp;
20
22
  constructor(platform: MorphPlatform, accessory: PlatformAccessory, config: ResolvedLightConfig);
21
23
  start(): Promise<void>;
@@ -28,6 +30,22 @@ export declare class MorphAccessory {
28
30
  * than saying nothing. Throwing a communication failure is how an accessory
29
31
  * reports itself as unavailable, and the Home app shows "No Response".
30
32
  */
33
+ /**
34
+ * Let a momentary switch spring back.
35
+ *
36
+ * HomeKit has no stateless switch that appears as one, so this is the usual
37
+ * shape: report the press, then push the characteristic back to off shortly
38
+ * after so it does not sit there claiming to be a state.
39
+ */
40
+ private release;
41
+ /**
42
+ * Name a service so the Home app shows it.
43
+ *
44
+ * `Name` alone is not enough: Home reads `ConfiguredName`, and without it
45
+ * every switch on an accessory shows under the accessory's own name — six
46
+ * controls all called "Desk Light".
47
+ */
48
+ private name;
31
49
  private live;
32
50
  /** Push "No Response" to every characteristic at once. */
33
51
  private markUnreachable;
package/dist/accessory.js CHANGED
@@ -1,6 +1,13 @@
1
1
  import { describeError } from './errors.js';
2
2
  import { DysonMorphLamp } from './dyson/lamp.js';
3
- import { kelvinToMired, miredToKelvin, MAX_KELVIN, MIN_KELVIN } from './dyson/protocol.js';
3
+ import { kelvinToMired, miredToKelvin, MAX_KELVIN, MIN_KELVIN, PRESETS } from './dyson/protocol.js';
4
+ /**
5
+ * How long a momentary switch stays on before springing back.
6
+ *
7
+ * Long enough that the Home app has drawn it as pressed, short enough that
8
+ * nobody reads it as a state the lamp is in.
9
+ */
10
+ const RELEASE_MS = 1_000;
4
11
  /**
5
12
  * Bridges one lamp's BLE session to its HomeKit services.
6
13
  *
@@ -14,8 +21,10 @@ export class MorphAccessory {
14
21
  accessory;
15
22
  config;
16
23
  lightbulb;
17
- motion;
18
24
  daylight;
25
+ autoBrightness;
26
+ movement;
27
+ presets = new Map();
19
28
  lamp;
20
29
  constructor(platform, accessory, config) {
21
30
  this.platform = platform;
@@ -59,15 +68,19 @@ export class MorphAccessory {
59
68
  this.lightbulb.updateCharacteristic(Characteristic.Brightness, state.brightness);
60
69
  this.lightbulb.updateCharacteristic(Characteristic.ColorTemperature, kelvinToMired(state.kelvin));
61
70
  this.daylight?.updateCharacteristic(Characteristic.On, state.daylight);
71
+ this.autoBrightness?.updateCharacteristic(Characteristic.On, state.autoBrightness);
72
+ this.movement?.updateCharacteristic(Characteristic.On, state.movement);
62
73
  });
63
74
  if (config.daylightSwitch !== false) {
64
75
  // A switch rather than a characteristic on the lightbulb: HomeKit renders
65
76
  // only the characteristics it knows, so a custom one would be invisible in
66
77
  // the Home app and reachable only from third-party clients.
78
+ // By subtype, not by type: this accessory carries more than one Switch,
79
+ // and a lookup by type alone would find whichever came first.
67
80
  this.daylight =
68
- this.accessory.getService(Service.Switch) ??
81
+ this.accessory.getServiceById(Service.Switch, 'daylight') ??
69
82
  this.accessory.addService(Service.Switch, `${config.name} Daylight`, 'daylight');
70
- this.daylight.setCharacteristic(Characteristic.Name, `${config.name} Daylight`);
83
+ this.name(this.daylight, 'Daylight');
71
84
  this.daylight
72
85
  .getCharacteristic(Characteristic.On)
73
86
  .onGet(() => this.live(() => this.lamp.getState().daylight))
@@ -76,16 +89,51 @@ export class MorphAccessory {
76
89
  // than leave it showing a state the lamp is not in.
77
90
  .onSet((value) => this.handleSet('daylight mode', () => this.lamp.setDaylight(value)));
78
91
  }
79
- if (config.motionSensor) {
80
- this.motion =
81
- this.accessory.getService(Service.MotionSensor) ??
82
- this.accessory.addService(Service.MotionSensor, `${config.name} Motion`);
83
- this.motion
84
- .getCharacteristic(Characteristic.MotionDetected)
85
- .onGet(() => this.live(() => this.motion?.getCharacteristic(Characteristic.MotionDetected).value ?? false));
86
- this.lamp.on('motion', (detected) => {
87
- this.motion?.updateCharacteristic(Characteristic.MotionDetected, detected);
88
- });
92
+ if (config.autoBrightnessSwitch !== false) {
93
+ this.autoBrightness =
94
+ this.accessory.getServiceById(Service.Switch, 'auto') ??
95
+ this.accessory.addService(Service.Switch, `${config.name} Auto Brightness`, 'auto');
96
+ this.name(this.autoBrightness, 'Auto Brightness');
97
+ this.autoBrightness
98
+ .getCharacteristic(Characteristic.On)
99
+ .onGet(() => this.live(() => this.lamp.getState().autoBrightness))
100
+ .onSet((value) => this.handleSet('auto brightness', () => this.lamp.setAutoBrightness(value)));
101
+ }
102
+ if (config.movementSwitch !== false) {
103
+ // Whether the lamp acts on what its sensor sees. Reading the sensor
104
+ // itself is not possible; see docs/PROTOCOL.md.
105
+ this.movement =
106
+ this.accessory.getServiceById(Service.Switch, 'movement') ??
107
+ this.accessory.addService(Service.Switch, `${config.name} Movement`, 'movement');
108
+ this.name(this.movement, 'Movement');
109
+ this.movement
110
+ .getCharacteristic(Characteristic.On)
111
+ .onGet(() => this.live(() => this.lamp.getState().movement))
112
+ .onSet((value) => this.handleSet('movement mode', () => this.lamp.setMovement(value)));
113
+ }
114
+ if (config.presetSwitches !== false) {
115
+ // Momentary rather than stateful. The lamp does hold a preset and reports
116
+ // which, but what these are for is applying a set of values — so pressing
117
+ // one applies it and the switch springs back, the way a scene does.
118
+ for (const preset of Object.keys(PRESETS)) {
119
+ // "Preset" in the name, so a momentary one is not mistaken in a list
120
+ // for the mode switches above it, which do hold a state.
121
+ const label = `${preset[0].toUpperCase() + preset.slice(1)} Preset`;
122
+ const service = this.accessory.getServiceById(Service.Switch, preset) ??
123
+ this.accessory.addService(Service.Switch, `${config.name} ${label}`, preset);
124
+ this.name(service, label);
125
+ service
126
+ .getCharacteristic(Characteristic.On)
127
+ .onGet(() => false)
128
+ .onSet(async (value) => {
129
+ if (!value) {
130
+ return;
131
+ }
132
+ await this.handleSet(`${label} preset`, () => this.lamp.setPreset(preset));
133
+ this.release(service);
134
+ });
135
+ this.presets.set(preset, service);
136
+ }
89
137
  }
90
138
  this.lamp.on('state', (state) => {
91
139
  this.lightbulb.updateCharacteristic(Characteristic.On, state.on);
@@ -94,6 +142,8 @@ export class MorphAccessory {
94
142
  // Follows the lamp leaving daylight mode on its own, which it does as soon
95
143
  // as colour temperature is set by hand.
96
144
  this.daylight?.updateCharacteristic(Characteristic.On, state.daylight);
145
+ this.autoBrightness?.updateCharacteristic(Characteristic.On, state.autoBrightness);
146
+ this.movement?.updateCharacteristic(Characteristic.On, state.movement);
97
147
  });
98
148
  }
99
149
  async start() {
@@ -115,6 +165,31 @@ export class MorphAccessory {
115
165
  * than saying nothing. Throwing a communication failure is how an accessory
116
166
  * reports itself as unavailable, and the Home app shows "No Response".
117
167
  */
168
+ /**
169
+ * Let a momentary switch spring back.
170
+ *
171
+ * HomeKit has no stateless switch that appears as one, so this is the usual
172
+ * shape: report the press, then push the characteristic back to off shortly
173
+ * after so it does not sit there claiming to be a state.
174
+ */
175
+ release(service) {
176
+ setTimeout(() => {
177
+ service.updateCharacteristic(this.platform.api.hap.Characteristic.On, false);
178
+ }, RELEASE_MS).unref();
179
+ }
180
+ /**
181
+ * Name a service so the Home app shows it.
182
+ *
183
+ * `Name` alone is not enough: Home reads `ConfiguredName`, and without it
184
+ * every switch on an accessory shows under the accessory's own name — six
185
+ * controls all called "Desk Light".
186
+ */
187
+ name(service, label) {
188
+ const { Characteristic } = this.platform.api.hap;
189
+ const full = `${this.config.name} ${label}`;
190
+ service.setCharacteristic(Characteristic.Name, full);
191
+ service.setCharacteristic(Characteristic.ConfiguredName, full);
192
+ }
118
193
  live(read) {
119
194
  if (!this.lamp.isConnected()) {
120
195
  throw new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
@@ -128,8 +203,9 @@ export class MorphAccessory {
128
203
  for (const characteristic of [Characteristic.On, Characteristic.Brightness, Characteristic.ColorTemperature]) {
129
204
  this.lightbulb.updateCharacteristic(characteristic, error);
130
205
  }
131
- this.motion?.updateCharacteristic(Characteristic.MotionDetected, error);
132
206
  this.daylight?.updateCharacteristic(Characteristic.On, error);
207
+ this.autoBrightness?.updateCharacteristic(Characteristic.On, error);
208
+ this.movement?.updateCharacteristic(Characteristic.On, error);
133
209
  }
134
210
  /**
135
211
  * Apply a write, reporting failure to HomeKit rather than swallowing it.
@@ -1 +1 @@
1
- {"version":3,"file":"accessory.js","sourceRoot":"","sources":["../src/accessory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"accessory.js","sourceRoot":"","sources":["../src/accessory.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -15,14 +15,23 @@ export interface LightConfig {
15
15
  ltk?: string;
16
16
  /** Dyson account GUID the LTK was issued to. Stored alongside the key. */
17
17
  accountId?: string;
18
- /** Expose the built-in motion sensor as a separate HomeKit service. */
19
- motionSensor?: boolean;
20
18
  /**
21
19
  * Expose daylight tracking as a switch. On by default: it is the lamp's
22
20
  * defining feature and there is no other way to turn it back on from HomeKit
23
21
  * once setting a colour temperature has ended it.
24
22
  */
25
23
  daylightSwitch?: boolean;
24
+ /**
25
+ * Expose the lamp's "Auto" brightness as a switch. On by default: it is a
26
+ * mode the lamp has and HomeKit would otherwise neither see nor reach.
27
+ */
28
+ autoBrightnessSwitch?: boolean;
29
+ /** Expose movement-triggered lighting as a switch. On by default. */
30
+ movementSwitch?: boolean;
31
+ /**
32
+ * Expose the lamp's preset modes as switches. On by default.
33
+ */
34
+ presetSwitches?: boolean;
26
35
  }
27
36
  /** A lamp whose credentials are known, from the config or the credential store. */
28
37
  export type ResolvedLightConfig = LightConfig & {
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAqDA;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAA2B,EAAE,KAAa;IAC5E,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,UAAU,KAAK,GAAG,CAAC;IAEjC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;QACxB,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,mBAAmB,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,sCAAsC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1E,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,8CAA8C,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpG,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;QAC1B,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,qBAAqB,CAAC,CAAC;IAC/C,CAAC;IACD,yEAAyE;IACzE,8EAA8E;IAC9E,4CAA4C;IAC5C,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACjG,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,wCAAwC,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QACjF,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,yCAAyC,CAAC,CAAC;IACnE,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,EAAE,CAAC;QAClE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,8FAA8F,CAAC,CAAC;IACxH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AA8DA;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAA2B,EAAE,KAAa;IAC5E,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,UAAU,KAAK,GAAG,CAAC;IAEjC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;QACxB,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,mBAAmB,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,sCAAsC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1E,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,8CAA8C,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpG,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;QAC1B,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,qBAAqB,CAAC,CAAC;IAC/C,CAAC;IACD,yEAAyE;IACzE,8EAA8E;IAC9E,4CAA4C;IAC5C,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACjG,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,wCAAwC,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QACjF,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,yCAAyC,CAAC,CAAC;IACnE,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,EAAE,CAAC;QAClE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,8FAA8F,CAAC,CAAC;IACxH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}