@switchbot/homebridge-switchbot 5.0.0-beta.111 → 5.0.0-beta.112

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.
@@ -75,12 +75,13 @@ body {
75
75
  system-ui,
76
76
  -apple-system,
77
77
  Arial;
78
- padding: 16px;
78
+ padding: 10px;
79
79
  }
80
80
 
81
81
  h1 {
82
- font-size: 24px;
82
+ font-size: 18px;
83
83
  margin-top: 0;
84
+ margin-bottom: 10px;
84
85
  }
85
86
 
86
87
  h2 {
@@ -152,25 +153,25 @@ code {
152
153
  }
153
154
 
154
155
  .form-group {
155
- margin-bottom: 16px;
156
+ margin-bottom: 10px;
156
157
  }
157
158
 
158
159
  label {
159
160
  display: block;
160
- margin-bottom: 6px;
161
+ margin-bottom: 4px;
161
162
  font-weight: 500;
162
- font-size: 12px;
163
+ font-size: 11px;
163
164
  color: #6b7280;
164
165
  }
165
166
 
166
167
  input {
167
168
  width: 100%;
168
169
  max-width: 400px;
169
- padding: 8px 10px;
170
+ padding: 6px 8px;
170
171
  border: 1px solid #d1d5db;
171
172
  border-radius: 6px;
172
173
  font-family: system-ui, -apple-system, monospace;
173
- font-size: 14px;
174
+ font-size: 12px;
174
175
  transition: all 0.2s ease;
175
176
  }
176
177
 
@@ -203,8 +204,8 @@ select:focus {
203
204
  }
204
205
 
205
206
  .status {
206
- font-size: 14px;
207
- margin-top: 4px;
207
+ font-size: 11px;
208
+ margin-top: 3px;
208
209
  }
209
210
 
210
211
  .status.ok {
@@ -221,27 +222,121 @@ select:focus {
221
222
  }
222
223
 
223
224
  .card {
224
- padding: 16px;
225
+ padding: 12px;
225
226
  border-radius: 8px;
226
- margin-bottom: 16px;
227
+ margin-bottom: 10px;
227
228
  }
228
229
 
229
- .device-item {
230
- padding: 10px 12px;
231
- border-radius: 6px;
230
+ .card.compact {
231
+ padding: 10px;
232
+ margin-bottom: 10px;
233
+ }
234
+
235
+ .card.compact h2 {
236
+ margin-top: 0;
237
+ margin-bottom: 6px;
238
+ font-size: 13px;
239
+ font-weight: 600;
240
+ }
241
+
242
+ .card.compact .form-group {
232
243
  margin-bottom: 6px;
244
+ }
245
+
246
+ .card.compact label {
247
+ font-size: 11px;
248
+ margin-bottom: 2px;
249
+ display: block;
250
+ }
251
+
252
+ .card.compact input {
253
+ padding: 5px 8px;
254
+ font-size: 12px;
255
+ }
256
+
257
+ .card.compact button {
258
+ padding: 6px 12px;
259
+ font-size: 12px;
260
+ }
261
+
262
+ .card.compact .status {
263
+ font-size: 11px;
264
+ margin-top: 4px;
265
+ }
266
+
267
+ .credentials-row {
268
+ display: flex;
269
+ flex-wrap: wrap;
270
+ gap: 8px;
271
+ }
272
+
273
+ .credentials-row .form-group {
274
+ flex: 1 1 100%;
275
+ min-width: 0;
276
+ }
277
+
278
+ @media (min-width: 700px) {
279
+ .credentials-row {
280
+ gap: 10px;
281
+ align-items: start;
282
+ }
283
+
284
+ .credentials-row .form-group {
285
+ flex: 1 1 calc(50% - 5px);
286
+ }
287
+ }
288
+
289
+ .device-item {
290
+ padding: 5px 8px;
291
+ border-radius: 5px;
292
+ margin-bottom: 0;
233
293
  display: flex;
234
- gap: 10px;
294
+ gap: 8px;
235
295
  align-items: center;
236
296
  justify-content: space-between;
237
297
  transition: all 0.2s ease;
298
+ height: 100%;
299
+ min-width: 0;
238
300
  }
239
301
 
240
302
  .device-item:hover {
241
- transform: translateY(-1px);
303
+ transform: translateY(-0.5px);
242
304
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
243
305
  }
244
306
 
307
+ .device-actions {
308
+ display: flex;
309
+ flex-wrap: wrap;
310
+ gap: 6px;
311
+ }
312
+
313
+ #devices.device-grid,
314
+ #discoveredDevices.device-grid,
315
+ ul.device-grid {
316
+ display: grid;
317
+ grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
318
+ gap: 6px;
319
+ padding-left: 0;
320
+ list-style: none;
321
+ margin: 0;
322
+ }
323
+
324
+ .device-item code {
325
+ display: inline-block;
326
+ max-width: 100%;
327
+ white-space: normal;
328
+ overflow-wrap: anywhere;
329
+ word-break: break-word;
330
+ }
331
+
332
+ @media (max-width: 900px) {
333
+ .device-actions {
334
+ width: 100%;
335
+ justify-content: flex-start !important;
336
+ margin-left: 0 !important;
337
+ }
338
+ }
339
+
245
340
  .card {
246
341
  padding: 16px;
247
342
  border-radius: 8px;
@@ -9,65 +9,45 @@
9
9
  <body>
10
10
  <h1>🤖 SwitchBot Configuration</h1>
11
11
 
12
- <div class="card">
12
+ <div class="card compact">
13
13
  <h2>API Credentials</h2>
14
- <p>
15
- Configure your SwitchBot API token and secret to enable device discovery
16
- and control.
17
- </p>
18
-
19
- <div class="form-group">
20
- <label for="token">API Token:</label>
21
- <input
22
- type="password"
23
- id="token"
24
- placeholder="Enter your SwitchBot API token"
25
- />
26
- <div class="status" id="tokenStatus"></div>
27
- </div>
28
-
29
- <div class="form-group">
30
- <label for="secret">API Secret:</label>
31
- <input
32
- type="password"
33
- id="secret"
34
- placeholder="Enter your SwitchBot API secret"
35
- />
36
- <div class="status" id="secretStatus"></div>
14
+ <div class="credentials-row">
15
+ <div class="form-group">
16
+ <label for="token">Token:</label>
17
+ <input type="password" id="token" placeholder="Enter token" />
18
+ <div class="status" id="tokenStatus"></div>
19
+ </div>
20
+ <div class="form-group">
21
+ <label for="secret">Secret:</label>
22
+ <input type="password" id="secret" placeholder="Enter secret" />
23
+ <div class="status" id="secretStatus"></div>
24
+ </div>
37
25
  </div>
38
-
39
- <button id="saveBtn" onclick="saveCredentials()">Save Credentials</button>
26
+ <button id="saveBtn" onclick="saveCredentials()">Save</button>
40
27
  <div id="saveStatus"></div>
41
28
  </div>
42
29
 
43
- <div class="card">
30
+ <div class="card compact">
44
31
  <h2>Discover Devices</h2>
45
- <p>
46
- Click "Discover" to find all devices available in your SwitchBot account
47
- and add them to your configuration.
48
- </p>
49
- <div style="margin-bottom: 16px">
50
- <label
51
- style="display: flex; align-items: center; gap: 8px; cursor: pointer"
52
- >
53
- <input
54
- type="checkbox"
55
- id="autoAddAllCheckbox"
56
- style="width: auto; margin: 0"
57
- />
58
- <span>Auto-add all discovered devices</span>
32
+ <div style="margin-bottom: 6px">
33
+ <label style="display: flex; align-items: center; gap: 4px; cursor: pointer; font-size: 11px">
34
+ <input type="checkbox" id="autoAddAllCheckbox" style="width: auto; margin: 0" />
35
+ <span>Auto-add all</span>
36
+ <span
37
+ title="When enabled, Discover immediately adds all found devices to your config. Existing devices are skipped automatically."
38
+ style="font-size: 11px; opacity: 0.7"
39
+ >ⓘ</span>
59
40
  </label>
41
+ <div style="margin-top: 2px; margin-left: 22px; font-size: 10px; opacity: 0.75; line-height: 1.25">
42
+ Adds all discovered devices automatically; already configured devices are skipped.
43
+ </div>
60
44
  </div>
61
- <button
62
- id="discoverBtn"
63
- onclick="discoverDevices()"
64
- style="margin-bottom: 16px"
65
- >
66
- 🔍 Discover Devices
45
+ <button id="discoverBtn" onclick="discoverDevices()" style="margin-bottom: 8px">
46
+ 🔍 Discover
67
47
  </button>
68
- <div id="discoverStatus" style="margin-bottom: 16px"></div>
48
+ <div id="discoverStatus" style="margin-bottom: 6px; font-size: 11px"></div>
69
49
  <div id="discoveredList" style="display: none">
70
- <h3 style="margin-top: 0">Available Devices</h3>
50
+ <h3 style="margin-top: 0; font-size: 12px; margin-bottom: 6px; font-weight: 600">Available Devices</h3>
71
51
  <ul
72
52
  id="discoveredDevices"
73
53
  style="max-height: 300px; overflow-y: auto"
@@ -75,22 +55,16 @@
75
55
  </div>
76
56
  </div>
77
57
 
78
- <div class="card">
58
+ <div class="card compact">
79
59
  <h2>Configured Devices</h2>
80
- <p>
81
- This page lists devices found in your Homebridge config for the
82
- SwitchBot platform. Use the copy button to insert device IDs into the
83
- plugin configuration. Connection preference (BLE/OpenAPI) is shown when
84
- available.
85
- </p>
86
60
  <div id="status">Loading…</div>
87
61
  <ul id="devices"></ul>
88
62
  <div
89
63
  id="removeAllContainer"
90
64
  style="
91
65
  display: none;
92
- margin-top: 16px;
93
- padding-top: 16px;
66
+ margin-top: 12px;
67
+ padding-top: 10px;
94
68
  border-top: 1px solid rgba(0, 0, 0, 0.1);
95
69
  "
96
70
  >
@@ -99,8 +73,8 @@
99
73
  style="
100
74
  background: #dc2626;
101
75
  width: 100%;
102
- padding: 10px 16px;
103
- font-size: 14px;
76
+ padding: 7px 12px;
77
+ font-size: 12px;
104
78
  font-weight: 500;
105
79
  "
106
80
  >
@@ -229,6 +229,19 @@ export async function discoverDevices(): Promise<void> {
229
229
  list.innerHTML = ''
230
230
  list.appendChild(controlsDiv)
231
231
 
232
+ // Create or get the device list container
233
+ let deviceListContainer = document.getElementById('discoveredDevices')
234
+ if (!deviceListContainer) {
235
+ deviceListContainer = document.createElement('ul')
236
+ deviceListContainer.id = 'discoveredDevices'
237
+ deviceListContainer.style.maxHeight = '400px'
238
+ deviceListContainer.style.overflowY = 'auto'
239
+ deviceListContainer.style.marginTop = '12px'
240
+ deviceListContainer.style.padding = '0'
241
+ deviceListContainer.style.listStyle = 'none'
242
+ list.appendChild(deviceListContainer)
243
+ }
244
+
232
245
  // Display discovery list
233
246
  list.style.display = 'block'
234
247
 
@@ -270,7 +283,18 @@ async function updateDiscoveryView(
270
283
  const ul = await renderDiscoveredDevices(sorted, {
271
284
  configuredIds,
272
285
  })
273
- document.getElementById('discoveredDevices')?.replaceWith(ul)
286
+
287
+ // Replace or append the rendered list
288
+ const existingList = document.getElementById('discoveredDevices')
289
+ if (existingList && existingList.parentNode) {
290
+ existingList.replaceWith(ul)
291
+ } else {
292
+ // Fallback: append to discovery list container
293
+ const listContainer = document.getElementById('discoveredList')
294
+ if (listContainer) {
295
+ listContainer.appendChild(ul)
296
+ }
297
+ }
274
298
  ul.id = 'discoveredDevices'
275
299
 
276
300
  // Update status with count
@@ -181,6 +181,7 @@ export async function renderDiscoveredDevices(
181
181
  options: { configuredIds?: Set<string> } = {},
182
182
  ): Promise<HTMLElement> {
183
183
  const ul = document.createElement('ul')
184
+ ul.className = 'device-grid'
184
185
  ul.style.maxHeight = '400px'
185
186
  ul.style.overflowY = 'auto'
186
187
  ul.style.marginTop = '12px'
@@ -198,26 +199,29 @@ export async function renderDiscoveredDevices(
198
199
  const li = document.createElement('li')
199
200
  li.className = 'device-item'
200
201
  li.style.display = 'flex'
201
- li.style.alignItems = 'center'
202
- li.style.justifyContent = 'space-between'
203
- li.style.padding = '10px 12px'
204
- li.style.marginBottom = '6px'
205
- li.style.borderRadius = '6px'
202
+ li.style.flexDirection = 'column'
203
+ li.style.alignItems = 'stretch'
204
+ li.style.justifyContent = 'flex-start'
205
+ li.style.padding = '5px 8px'
206
+ li.style.marginBottom = '0'
207
+ li.style.borderRadius = '5px'
206
208
  li.style.transition = 'all 0.2s ease'
207
209
 
208
210
  const info = document.createElement('div')
209
- info.style.flex = '1'
211
+ info.style.flex = '1 1 auto'
212
+ info.style.width = '100%'
213
+ info.style.minWidth = '0'
210
214
 
211
215
  const nameContainer = document.createElement('div')
212
216
  nameContainer.style.display = 'flex'
213
217
  nameContainer.style.alignItems = 'center'
214
- nameContainer.style.marginBottom = '4px'
218
+ nameContainer.style.marginBottom = '0'
215
219
  nameContainer.style.flexWrap = 'wrap'
216
- nameContainer.style.gap = '6px'
220
+ nameContainer.style.gap = '4px'
217
221
 
218
222
  const name = document.createElement('div')
219
223
  name.style.fontWeight = '500'
220
- name.style.fontSize = '14px'
224
+ name.style.fontSize = '13px'
221
225
  name.textContent = d.name || d.id
222
226
 
223
227
  nameContainer.appendChild(name)
@@ -225,8 +229,8 @@ export async function renderDiscoveredDevices(
225
229
  const duplicateBadge = document.createElement('span')
226
230
  duplicateBadge.textContent = alreadyAdded ? '✓ Already Added' : '➕ New Device'
227
231
  duplicateBadge.style.cssText = alreadyAdded
228
- ? 'background: #16a34a; color: white; padding: 2px 6px; border-radius: 3px; font-size: 10px; font-weight: 600;'
229
- : 'background: #2563eb; color: white; padding: 2px 6px; border-radius: 3px; font-size: 10px; font-weight: 600;'
232
+ ? 'background: #16a34a; color: white; padding: 1px 5px; border-radius: 3px; font-size: 9px; font-weight: 600;'
233
+ : 'background: #2563eb; color: white; padding: 1px 5px; border-radius: 3px; font-size: 9px; font-weight: 600;'
230
234
  nameContainer.appendChild(duplicateBadge)
231
235
 
232
236
  // Add connection type badge
@@ -247,10 +251,13 @@ export async function renderDiscoveredDevices(
247
251
  }
248
252
 
249
253
  const details = document.createElement('div')
250
- details.style.fontSize = '11px'
254
+ details.style.fontSize = '10px'
251
255
  details.style.opacity = '0.7'
252
- details.style.marginTop = '4px'
256
+ details.style.marginTop = '0'
253
257
  details.style.fontFamily = 'monospace'
258
+ details.style.whiteSpace = 'normal'
259
+ details.style.overflowWrap = 'anywhere'
260
+ details.style.wordBreak = 'break-word'
254
261
 
255
262
  let detailsText = `ID: ${d.id} | Type: ${d.type} | Model: ${d.model || 'N/A'}`
256
263
  if (d.hubDeviceId) { detailsText += ` | Hub: ${d.hubDeviceId}` }
@@ -262,9 +269,10 @@ export async function renderDiscoveredDevices(
262
269
 
263
270
  const addBtn = document.createElement('button')
264
271
  addBtn.textContent = alreadyAdded ? 'Already Added' : 'Add to Config'
265
- addBtn.style.marginLeft = '8px'
266
- addBtn.style.padding = '6px 14px'
267
- addBtn.style.fontSize = '12px'
272
+ addBtn.style.marginLeft = '0'
273
+ addBtn.style.marginTop = '2px'
274
+ addBtn.style.padding = '4px 9px'
275
+ addBtn.style.fontSize = '11px'
268
276
  addBtn.style.whiteSpace = 'nowrap'
269
277
  addBtn.style.flexShrink = '0'
270
278
  addBtn.disabled = alreadyAdded
@@ -284,17 +292,24 @@ export async function renderDiscoveredDevices(
284
292
  const viewBtn = document.createElement('button')
285
293
  viewBtn.textContent = 'View in Config'
286
294
  viewBtn.className = 'secondary'
287
- viewBtn.style.marginLeft = '8px'
288
- viewBtn.style.padding = '6px 12px'
289
- viewBtn.style.fontSize = '12px'
295
+ viewBtn.style.marginLeft = '0'
296
+ viewBtn.style.padding = '4px 9px'
297
+ viewBtn.style.fontSize = '11px'
290
298
  viewBtn.onclick = async () => {
291
299
  await loadConfiguredDevices()
292
300
  scrollToConfiguredDevice(d.id)
293
301
  }
294
302
  li.appendChild(info)
295
303
  const actions = document.createElement('div')
304
+ actions.className = 'device-actions'
296
305
  actions.style.display = 'flex'
297
306
  actions.style.alignItems = 'center'
307
+ actions.style.flexWrap = 'wrap'
308
+ actions.style.justifyContent = 'flex-start'
309
+ actions.style.marginLeft = '0'
310
+ actions.style.width = '100%'
311
+ actions.style.marginTop = '2px'
312
+ actions.style.gap = '5px'
298
313
  actions.appendChild(viewBtn)
299
314
  actions.appendChild(addBtn)
300
315
  li.appendChild(actions)
@@ -302,8 +317,19 @@ export async function renderDiscoveredDevices(
302
317
  continue
303
318
  }
304
319
 
320
+ const actions = document.createElement('div')
321
+ actions.className = 'device-actions'
322
+ actions.style.display = 'flex'
323
+ actions.style.flexWrap = 'wrap'
324
+ actions.style.justifyContent = 'flex-start'
325
+ actions.style.marginLeft = '0'
326
+ actions.style.width = '100%'
327
+ actions.style.marginTop = '2px'
328
+ actions.style.gap = '5px'
329
+ actions.appendChild(addBtn)
330
+
305
331
  li.appendChild(info)
306
- li.appendChild(addBtn)
332
+ li.appendChild(actions)
307
333
  ul.appendChild(li)
308
334
  }
309
335
 
@@ -474,6 +500,7 @@ export function renderDeviceList(list: any[]): void {
474
500
  }
475
501
 
476
502
  status.textContent = `Found ${list.length} device(s)`
503
+ ul.classList.add('device-grid')
477
504
  ul.innerHTML = ''
478
505
 
479
506
  // Show remove all button when devices exist
@@ -485,25 +512,36 @@ export function renderDeviceList(list: any[]): void {
485
512
  const li = document.createElement('li')
486
513
  li.className = 'device-item'
487
514
  li.setAttribute('data-device-id', normalizeId(d.id))
515
+ li.style.display = 'flex'
516
+ li.style.flexDirection = 'column'
517
+ li.style.alignItems = 'stretch'
518
+ li.style.marginBottom = '0'
488
519
 
489
520
  const info = document.createElement('div')
490
- info.style.flex = '1'
521
+ info.style.flex = '1 1 auto'
522
+ info.style.width = '100%'
523
+ info.style.minWidth = '0'
491
524
 
492
525
  const nameContainer = document.createElement('div')
493
526
  nameContainer.style.display = 'flex'
494
- nameContainer.style.alignItems = 'center'
495
- nameContainer.style.flexWrap = 'wrap'
496
- nameContainer.style.gap = '6px'
527
+ nameContainer.style.flexDirection = 'column'
528
+ nameContainer.style.alignItems = 'flex-start'
529
+ nameContainer.style.gap = '0'
497
530
 
498
531
  const name = document.createElement('div')
499
532
  name.style.fontWeight = '500'
533
+ name.style.fontSize = '13px'
500
534
  name.textContent = d.name || d.id
501
535
 
502
536
  const code = document.createElement('code')
503
537
  code.textContent = d.id
504
- code.style.fontSize = '12px'
538
+ code.style.fontSize = '10px'
505
539
  code.style.opacity = '0.75'
506
- code.style.marginLeft = '8px'
540
+ code.style.marginLeft = '0'
541
+ code.style.whiteSpace = 'normal'
542
+ code.style.overflowWrap = 'anywhere'
543
+ code.style.wordBreak = 'break-word'
544
+ code.style.maxWidth = '100%'
507
545
 
508
546
  nameContainer.appendChild(name)
509
547
  nameContainer.appendChild(code)
@@ -516,8 +554,8 @@ export function renderDeviceList(list: any[]): void {
516
554
 
517
555
  const meta = document.createElement('div')
518
556
  meta.style.opacity = '0.75'
519
- meta.style.marginTop = '4px'
520
- meta.style.fontSize = '12px'
557
+ meta.style.marginTop = '0'
558
+ meta.style.fontSize = '11px'
521
559
 
522
560
  const typeText = d.type ? `type: ${d.type}` : ''
523
561
  const connText = d.connectionPreference ? `conn: ${d.connectionPreference}` : ''
@@ -528,13 +566,19 @@ export function renderDeviceList(list: any[]): void {
528
566
  info.appendChild(meta)
529
567
 
530
568
  const buttons = document.createElement('div')
569
+ buttons.className = 'device-actions'
531
570
  buttons.style.display = 'flex'
532
- buttons.style.gap = '8px'
571
+ buttons.style.flexWrap = 'wrap'
572
+ buttons.style.justifyContent = 'flex-start'
573
+ buttons.style.marginLeft = '0'
574
+ buttons.style.width = '100%'
575
+ buttons.style.marginTop = '2px'
576
+ buttons.style.gap = '5px'
533
577
 
534
578
  const editBtn = document.createElement('button')
535
579
  editBtn.textContent = '✏️ Edit'
536
- editBtn.style.padding = '6px 12px'
537
- editBtn.style.fontSize = '12px'
580
+ editBtn.style.padding = '4px 9px'
581
+ editBtn.style.fontSize = '11px'
538
582
  editBtn.onclick = async () => {
539
583
  const { editDevice } = await import('./modals.js')
540
584
  await editDevice(d)
@@ -542,8 +586,8 @@ export function renderDeviceList(list: any[]): void {
542
586
 
543
587
  const copyBtn = document.createElement('button')
544
588
  copyBtn.textContent = 'Copy ID'
545
- copyBtn.style.padding = '6px 12px'
546
- copyBtn.style.fontSize = '12px'
589
+ copyBtn.style.padding = '4px 9px'
590
+ copyBtn.style.fontSize = '11px'
547
591
  copyBtn.addEventListener('click', async () => {
548
592
  try {
549
593
  await navigator.clipboard.writeText(d.id)
@@ -560,8 +604,8 @@ export function renderDeviceList(list: any[]): void {
560
604
 
561
605
  const deleteBtn = document.createElement('button')
562
606
  deleteBtn.textContent = '🗑️ Delete'
563
- deleteBtn.style.padding = '6px 12px'
564
- deleteBtn.style.fontSize = '12px'
607
+ deleteBtn.style.padding = '4px 9px'
608
+ deleteBtn.style.fontSize = '11px'
565
609
  deleteBtn.style.background = '#ef4444'
566
610
  deleteBtn.onclick = async () => {
567
611
  const { deleteDeviceFromConfig } = await import('./devices-delete.js')
package/src/platform.ts CHANGED
@@ -132,12 +132,7 @@ const DEVICE_MATTER_CLUSTERS: Record<string, any> = {
132
132
  minLevel: 0,
133
133
  maxLevel: 254,
134
134
  },
135
- colorControl: {
136
- currentHue: 0,
137
- currentSaturation: 0,
138
- colorTemperatureMireds: 400,
139
- colorMode: 0,
140
- },
135
+ colorControl: {},
141
136
  }, // Lightbulb with color → OnOff + LevelControl + ColorControl
142
137
  lock: {
143
138
  doorLock: {
@@ -1,21 +1,21 @@
1
- import { describe, test } from 'vitest'
2
- import { promisify } from 'util'
3
- import { execFile } from 'child_process'
4
- import path from 'path'
1
+ import { execFile } from 'node:child_process'
2
+ import path from 'node:path'
3
+ import { promisify } from 'node:util'
4
+ import { describe, it } from 'vitest'
5
5
 
6
6
  const execFileP = promisify(execFile)
7
7
 
8
- describe('E2E scripts (manual-run harness)', () => {
8
+ describe('e2e scripts (manual-run harness)', () => {
9
9
  if (!process.env.RUN_E2E) {
10
- test.skip('E2E disabled - set RUN_E2E=true to enable', () => {})
10
+ it.skip('e2e disabled - set RUN_E2E=true to enable', () => {})
11
11
  return
12
12
  }
13
13
 
14
- test('run configured E2E scripts sequentially', async () => {
14
+ it('should run configured e2e scripts sequentially', async () => {
15
15
  const repoRoot = path.resolve(__dirname, '../../')
16
16
  const scriptsDir = path.join(repoRoot, 'scripts', 'e2e')
17
17
 
18
- const scriptsToRun: { envVar: string; script: string }[] = [
18
+ const scriptsToRun: { envVar: string, script: string }[] = [
19
19
  { envVar: 'LIGHT_ACCESSORY_ID', script: 'light-e2e.sh' },
20
20
  { envVar: 'FAN_ACCESSORY_ID', script: 'fan-e2e.sh' },
21
21
  { envVar: 'CURTAIN_ACCESSORY_ID', script: 'curtain-e2e.sh' },
@@ -32,7 +32,7 @@ describe('E2E scripts (manual-run harness)', () => {
32
32
 
33
33
  const scriptPath = path.join(scriptsDir, s.script)
34
34
  // Forward environment so scripts can read HB_URL / HB_TOKEN / <ACCESSORY_ID>
35
- const env = Object.assign({}, process.env)
35
+ const env = { ...process.env }
36
36
 
37
37
  try {
38
38
  // eslint-disable-next-line no-console
@@ -40,7 +40,9 @@ describe('E2E scripts (manual-run harness)', () => {
40
40
  const { stdout, stderr } = await execFileP('bash', [scriptPath], { env })
41
41
  // eslint-disable-next-line no-console
42
42
  console.log(stdout)
43
- if (stderr) console.error(stderr)
43
+ if (stderr) {
44
+ console.error(stderr)
45
+ }
44
46
  } catch (e: any) {
45
47
  // bubble up as test failure
46
48
  throw new Error(`Script ${s.script} failed: ${e.message}`)
@@ -47,7 +47,7 @@ export function makeFakeApiWithoutMatter() {
47
47
  isMatterEnabled: () => false,
48
48
  hap: makeFakeHap(),
49
49
  platformAccessory: PlatformAccessory,
50
- registerPlatformAccessories: (_p: string, _n: string, accs: any[]) => {},
51
- on: (_ev: string, cb: Function) => {},
50
+ registerPlatformAccessories: () => {},
51
+ on: () => {},
52
52
  }
53
53
  }