@switchbot/homebridge-switchbot 5.0.0-beta.134 → 5.0.0-beta.136
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/config.schema.json +0 -11
- package/dist/deviceFactory.d.ts +3 -1
- package/dist/deviceFactory.d.ts.map +1 -1
- package/dist/deviceFactory.js +3 -18
- package/dist/deviceFactory.js.map +1 -1
- package/dist/devices/genericDevice.d.ts +1 -1
- package/dist/devices/genericDevice.d.ts.map +1 -1
- package/dist/devices/genericDevice.js +79 -159
- package/dist/devices/genericDevice.js.map +1 -1
- package/dist/homebridge-ui/public/index.html +107 -124
- package/dist/homebridge-ui/public/js/api.d.ts +1 -4
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/api.js +1 -7
- package/dist/homebridge-ui/public/js/api.js.map +1 -1
- package/dist/homebridge-ui/public/js/api.ts +1 -8
- package/dist/homebridge-ui/public/js/app.js +201 -90
- package/dist/homebridge-ui/public/js/app.js.map +2 -2
- package/dist/homebridge-ui/public/js/app.ts +5 -6
- package/dist/homebridge-ui/public/js/credentials.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/credentials.js +1 -1
- package/dist/homebridge-ui/public/js/credentials.js.map +1 -1
- package/dist/homebridge-ui/public/js/credentials.ts +7 -3
- package/dist/homebridge-ui/public/js/devices-delete.js +1 -1
- package/dist/homebridge-ui/public/js/devices-delete.js.map +1 -1
- package/dist/homebridge-ui/public/js/devices-delete.ts +1 -1
- package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/devices.js +0 -1
- package/dist/homebridge-ui/public/js/devices.js.map +1 -1
- package/dist/homebridge-ui/public/js/devices.ts +0 -2
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.js +6 -3
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.ts +9 -3
- package/dist/homebridge-ui/public/js/logger.d.ts +1 -0
- package/dist/homebridge-ui/public/js/logger.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/logger.js +8 -3
- package/dist/homebridge-ui/public/js/logger.js.map +1 -1
- package/dist/homebridge-ui/public/js/logger.ts +12 -6
- package/dist/homebridge-ui/public/js/modals.d.ts +4 -0
- package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/modals.js +152 -59
- package/dist/homebridge-ui/public/js/modals.js.map +1 -1
- package/dist/homebridge-ui/public/js/modals.ts +187 -60
- package/dist/homebridge-ui/public/js/render.d.ts +3 -0
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/render.js +63 -24
- package/dist/homebridge-ui/public/js/render.js.map +1 -1
- package/dist/homebridge-ui/public/js/render.ts +102 -51
- package/dist/homebridge-ui/utils/logger.js +1 -1
- package/dist/homebridge-ui/utils/logger.js.map +1 -1
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +40 -32
- package/dist/platform.js.map +1 -1
- package/dist/switchbotClient.d.ts +5 -5
- package/dist/switchbotClient.d.ts.map +1 -1
- package/dist/switchbotClient.js +21 -12
- package/dist/switchbotClient.js.map +1 -1
- package/docs/variables/default.html +1 -1
- package/package.json +1 -1
- package/scripts/build-ui.js +4 -3
- package/scripts/generate-matter-maps.js +34 -17
- package/scripts/sync-device-types.mjs +4 -1
- package/src/deviceFactory.ts +3 -18
- package/src/devices/genericDevice.ts +77 -164
- package/src/homebridge-ui/public/index.html +107 -124
- package/src/homebridge-ui/public/js/api.ts +1 -8
- package/src/homebridge-ui/public/js/app.ts +5 -6
- package/src/homebridge-ui/public/js/credentials.ts +7 -3
- package/src/homebridge-ui/public/js/devices-delete.ts +1 -1
- package/src/homebridge-ui/public/js/devices.ts +0 -2
- package/src/homebridge-ui/public/js/discovery.ts +9 -3
- package/src/homebridge-ui/public/js/logger.ts +12 -6
- package/src/homebridge-ui/public/js/modals.ts +187 -60
- package/src/homebridge-ui/public/js/render.ts +102 -51
- package/src/homebridge-ui/utils/logger.ts +1 -1
- package/src/platform.ts +40 -31
- package/src/switchbotClient.ts +42 -27
- package/test/accessory-restore.spec.ts +9 -8
- package/test/device-mapping.spec.ts +4 -3
- package/test/deviceFactory.spec.ts +4 -3
- package/test/e2e/run-e2e.spec.ts +6 -10
- package/test/fan-swing.spec.ts +7 -6
- package/test/helpers/matter-harness.ts +18 -7
- package/test/lock-users.spec.ts +5 -5
- package/test/matter-childbridge.spec.ts +10 -7
- package/test/matter-descriptors.spec.ts +8 -8
- package/test/matter-device-state.spec.ts +52 -36
- package/test/matter-integration.spec.ts +53 -6
- package/test/platform.integration.spec.ts +7 -5
- package/test/switchbot-client-debounce.spec.ts +36 -40
- package/test/switchbot-client-openapi.spec.ts +22 -15
- package/test/switchbotClient.spec.ts +4 -3
- package/test/utils.spec.ts +2 -1
|
@@ -15,7 +15,9 @@ export async function loadCredentialStatus(): Promise<void> {
|
|
|
15
15
|
const tokenStatus = document.getElementById('tokenStatus')
|
|
16
16
|
const secretStatus = document.getElementById('secretStatus')
|
|
17
17
|
|
|
18
|
-
if (!tokenStatus || !secretStatus) {
|
|
18
|
+
if (!tokenStatus || !secretStatus) {
|
|
19
|
+
return
|
|
20
|
+
}
|
|
19
21
|
|
|
20
22
|
if (creds.hasToken) {
|
|
21
23
|
tokenStatus.textContent = `✓ Configured (${creds.tokenLength} characters)`
|
|
@@ -43,7 +45,9 @@ export async function saveCredentials(): Promise<void> {
|
|
|
43
45
|
const saveStatus = document.getElementById('saveStatus')
|
|
44
46
|
const saveBtn = document.getElementById('saveBtn') as HTMLButtonElement
|
|
45
47
|
|
|
46
|
-
if (!saveStatus || !saveBtn) {
|
|
48
|
+
if (!saveStatus || !saveBtn) {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
47
51
|
|
|
48
52
|
if (!token || !secret) {
|
|
49
53
|
saveStatus.textContent = 'Please enter both token and secret'
|
|
@@ -80,7 +84,7 @@ export async function saveCredentials(): Promise<void> {
|
|
|
80
84
|
;(document.getElementById('secret') as HTMLInputElement).value = ''
|
|
81
85
|
|
|
82
86
|
// Reload status to verify save
|
|
83
|
-
setTimeout(
|
|
87
|
+
setTimeout(loadCredentialStatus, 500)
|
|
84
88
|
|
|
85
89
|
// Clear status message
|
|
86
90
|
setTimeout(() => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { deleteAllDevices as apiDeleteAllDevices, deleteDevice as apiDeleteDevice, fetchDevices, syncParentPluginConfigFromDisk } from './api.js'
|
|
2
2
|
import { uiLog } from './logger.js'
|
|
3
3
|
import { hideBusyUi, showBusyUi } from './modal.js'
|
|
4
4
|
import { renderDeviceList } from './render.js'
|
|
@@ -10,7 +10,6 @@ type ImportDiscoveredDeviceResult = {
|
|
|
10
10
|
address?: string
|
|
11
11
|
encryptionKey?: string
|
|
12
12
|
keyId?: string
|
|
13
|
-
matterType?: number
|
|
14
13
|
} | null
|
|
15
14
|
|
|
16
15
|
export async function addDeviceToConfig(device: any, options: { refresh?: boolean, showStatus?: boolean } = {}): Promise<{ added: boolean }> {
|
|
@@ -32,7 +31,6 @@ export async function addDeviceToConfig(device: any, options: { refresh?: boolea
|
|
|
32
31
|
rssi: device.rssi,
|
|
33
32
|
encryptionKey: importValues.encryptionKey,
|
|
34
33
|
keyId: importValues.keyId,
|
|
35
|
-
matterType: importValues.matterType,
|
|
36
34
|
})
|
|
37
35
|
uiLog.info('Add device response:', resp)
|
|
38
36
|
|
|
@@ -1301,9 +1301,15 @@ async function updateDiscoveryView(
|
|
|
1301
1301
|
const enableSelectedBtn = document.querySelector('button')?.parentElement?.querySelector('button[aria-label="Enable Selected"]') as HTMLButtonElement | null
|
|
1302
1302
|
const disableSelectedBtn = document.querySelector('button')?.parentElement?.querySelector('button[aria-label="Disable Selected"]') as HTMLButtonElement | null
|
|
1303
1303
|
const hasSelection = selectedIds.size > 0
|
|
1304
|
-
if (addSelectedBtn)
|
|
1305
|
-
|
|
1306
|
-
|
|
1304
|
+
if (addSelectedBtn) {
|
|
1305
|
+
addSelectedBtn.disabled = !hasSelection
|
|
1306
|
+
}
|
|
1307
|
+
if (enableSelectedBtn) {
|
|
1308
|
+
enableSelectedBtn.disabled = !hasSelection
|
|
1309
|
+
}
|
|
1310
|
+
if (disableSelectedBtn) {
|
|
1311
|
+
disableSelectedBtn.disabled = !hasSelection
|
|
1312
|
+
}
|
|
1307
1313
|
}
|
|
1308
1314
|
window.removeEventListener('discovery-selection-changed', updateBatchButtonStates)
|
|
1309
1315
|
window.addEventListener('discovery-selection-changed', updateBatchButtonStates)
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
const PREFIX = '[SwitchBot UI/html]'
|
|
3
|
+
|
|
1
4
|
export const uiLog = {
|
|
2
|
-
info: (message: string, ...parameters: any[])
|
|
3
|
-
console.
|
|
5
|
+
info: (message: string, ...parameters: any[]) => {
|
|
6
|
+
console.log(PREFIX, message, ...parameters)
|
|
4
7
|
},
|
|
5
|
-
warn: (message: string, ...parameters: any[])
|
|
6
|
-
console.warn(
|
|
8
|
+
warn: (message: string, ...parameters: any[]) => {
|
|
9
|
+
console.warn(PREFIX, message, ...parameters)
|
|
7
10
|
},
|
|
8
|
-
error: (message: string, ...parameters: any[])
|
|
9
|
-
console.error(
|
|
11
|
+
error: (message: string, ...parameters: any[]) => {
|
|
12
|
+
console.error(PREFIX, message, ...parameters)
|
|
13
|
+
},
|
|
14
|
+
debug: (message: string, ...parameters: any[]) => {
|
|
15
|
+
console.debug(PREFIX, message, ...parameters)
|
|
10
16
|
},
|
|
11
17
|
}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { DEVICE_TYPES } from './constants.js'
|
|
2
2
|
import { uiLog } from './logger.js'
|
|
3
3
|
|
|
4
|
-
export async function importDiscoveredDevice(device: any): Promise<{
|
|
4
|
+
export async function importDiscoveredDevice(device: any): Promise<{
|
|
5
|
+
configDeviceName: string
|
|
6
|
+
configDeviceType: string
|
|
7
|
+
address?: string
|
|
8
|
+
connectionPreference?: string
|
|
9
|
+
room?: string
|
|
10
|
+
encryptionKey?: string
|
|
11
|
+
keyId?: string
|
|
12
|
+
} | null> {
|
|
5
13
|
return new Promise((resolve) => {
|
|
6
14
|
const div = document.createElement('div')
|
|
7
15
|
div.style.position = 'fixed'
|
|
@@ -91,6 +99,51 @@ export async function importDiscoveredDevice(device: any): Promise<{ configDevic
|
|
|
91
99
|
typeSelect.appendChild(optgroup)
|
|
92
100
|
})
|
|
93
101
|
|
|
102
|
+
// --- Connection Preference ---
|
|
103
|
+
const connectionPrefLabel = document.createElement('label')
|
|
104
|
+
connectionPrefLabel.textContent = 'Connection Preference'
|
|
105
|
+
connectionPrefLabel.style.display = 'block'
|
|
106
|
+
connectionPrefLabel.style.marginBottom = '6px'
|
|
107
|
+
connectionPrefLabel.style.fontWeight = '500'
|
|
108
|
+
connectionPrefLabel.style.fontSize = '12px'
|
|
109
|
+
connectionPrefLabel.style.color = '#6b7280'
|
|
110
|
+
|
|
111
|
+
const connectionPrefSelect = document.createElement('select')
|
|
112
|
+
connectionPrefSelect.style.width = '100%'
|
|
113
|
+
connectionPrefSelect.style.marginBottom = '12px'
|
|
114
|
+
connectionPrefSelect.style.padding = '8px 10px'
|
|
115
|
+
connectionPrefSelect.style.borderRadius = '6px'
|
|
116
|
+
connectionPrefSelect.style.fontSize = '14px'
|
|
117
|
+
connectionPrefSelect.style.boxSizing = 'border-box';
|
|
118
|
+
['auto', 'ble', 'openapi'].forEach((val) => {
|
|
119
|
+
const opt = document.createElement('option')
|
|
120
|
+
opt.value = val
|
|
121
|
+
opt.text = val.charAt(0).toUpperCase() + val.slice(1)
|
|
122
|
+
opt.selected = (device.connectionPreference || 'auto') === val
|
|
123
|
+
connectionPrefSelect.appendChild(opt)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
// --- Room ---
|
|
127
|
+
const roomLabel = document.createElement('label')
|
|
128
|
+
roomLabel.textContent = 'Room'
|
|
129
|
+
roomLabel.style.display = 'block'
|
|
130
|
+
roomLabel.style.marginBottom = '6px'
|
|
131
|
+
roomLabel.style.fontWeight = '500'
|
|
132
|
+
roomLabel.style.fontSize = '12px'
|
|
133
|
+
roomLabel.style.color = '#6b7280'
|
|
134
|
+
|
|
135
|
+
const roomInput = document.createElement('input')
|
|
136
|
+
roomInput.type = 'text'
|
|
137
|
+
roomInput.value = device.room || ''
|
|
138
|
+
roomInput.placeholder = 'Optional room/location metadata'
|
|
139
|
+
roomInput.style.width = '100%'
|
|
140
|
+
roomInput.style.marginBottom = '12px'
|
|
141
|
+
roomInput.style.padding = '8px 10px'
|
|
142
|
+
roomInput.style.borderRadius = '6px'
|
|
143
|
+
roomInput.style.fontSize = '14px'
|
|
144
|
+
roomInput.style.boxSizing = 'border-box'
|
|
145
|
+
|
|
146
|
+
// --- BLE MAC Address ---
|
|
94
147
|
const macLabel = document.createElement('label')
|
|
95
148
|
macLabel.textContent = 'BLE MAC Address (optional)'
|
|
96
149
|
macLabel.style.display = 'block'
|
|
@@ -110,7 +163,7 @@ export async function importDiscoveredDevice(device: any): Promise<{ configDevic
|
|
|
110
163
|
macInput.style.fontSize = '14px'
|
|
111
164
|
macInput.style.boxSizing = 'border-box'
|
|
112
165
|
|
|
113
|
-
//
|
|
166
|
+
// --- Encryption Key ---
|
|
114
167
|
const encryptionKeyLabel = document.createElement('label')
|
|
115
168
|
encryptionKeyLabel.textContent = 'BLE Encryption Key (optional)'
|
|
116
169
|
encryptionKeyLabel.style.display = 'block'
|
|
@@ -130,7 +183,7 @@ export async function importDiscoveredDevice(device: any): Promise<{ configDevic
|
|
|
130
183
|
encryptionKeyInput.style.fontSize = '14px'
|
|
131
184
|
encryptionKeyInput.style.boxSizing = 'border-box'
|
|
132
185
|
|
|
133
|
-
//
|
|
186
|
+
// --- Key ID ---
|
|
134
187
|
const keyIdLabel = document.createElement('label')
|
|
135
188
|
keyIdLabel.textContent = 'BLE Key ID (optional)'
|
|
136
189
|
keyIdLabel.style.display = 'block'
|
|
@@ -171,7 +224,15 @@ export async function importDiscoveredDevice(device: any): Promise<{ configDevic
|
|
|
171
224
|
importBtn.style.padding = '8px 20px'
|
|
172
225
|
importBtn.style.fontSize = '13px'
|
|
173
226
|
|
|
174
|
-
const cleanup = (result: {
|
|
227
|
+
const cleanup = (result: {
|
|
228
|
+
configDeviceName: string
|
|
229
|
+
configDeviceType: string
|
|
230
|
+
address?: string
|
|
231
|
+
connectionPreference?: string
|
|
232
|
+
room?: string
|
|
233
|
+
encryptionKey?: string
|
|
234
|
+
keyId?: string
|
|
235
|
+
} | null) => {
|
|
175
236
|
div.remove()
|
|
176
237
|
resolve(result)
|
|
177
238
|
}
|
|
@@ -181,6 +242,8 @@ export async function importDiscoveredDevice(device: any): Promise<{ configDevic
|
|
|
181
242
|
configDeviceName: nameInput.value || device.name || device.id,
|
|
182
243
|
configDeviceType: typeSelect.value || device.type,
|
|
183
244
|
address: macInput.value || undefined,
|
|
245
|
+
connectionPreference: connectionPrefSelect.value || undefined,
|
|
246
|
+
room: roomInput.value || undefined,
|
|
184
247
|
encryptionKey: encryptionKeyInput.value || undefined,
|
|
185
248
|
keyId: keyIdInput.value || undefined,
|
|
186
249
|
})
|
|
@@ -197,6 +260,10 @@ export async function importDiscoveredDevice(device: any): Promise<{ configDevic
|
|
|
197
260
|
contentDiv.appendChild(nameInput)
|
|
198
261
|
contentDiv.appendChild(typeLabel)
|
|
199
262
|
contentDiv.appendChild(typeSelect)
|
|
263
|
+
contentDiv.appendChild(connectionPrefLabel)
|
|
264
|
+
contentDiv.appendChild(connectionPrefSelect)
|
|
265
|
+
contentDiv.appendChild(roomLabel)
|
|
266
|
+
contentDiv.appendChild(roomInput)
|
|
200
267
|
contentDiv.appendChild(macLabel)
|
|
201
268
|
contentDiv.appendChild(macInput)
|
|
202
269
|
contentDiv.appendChild(encryptionKeyLabel)
|
|
@@ -250,58 +317,6 @@ export async function editDevice(device: any): Promise<void> {
|
|
|
250
317
|
typeSelect.appendChild(optgroup)
|
|
251
318
|
})
|
|
252
319
|
|
|
253
|
-
// --- Matter Type Advanced Field (only for window covering types) ---
|
|
254
|
-
const windowCoveringTypes = ['Roller Shade', 'Curtain', 'Curtain3', 'Blind Tilt']
|
|
255
|
-
const showMatterType = windowCoveringTypes.includes(device.configDeviceType || device.deviceType || device.type || '')
|
|
256
|
-
const matterTypeLabel = document.createElement('label')
|
|
257
|
-
matterTypeLabel.textContent = 'Matter Window Covering Type (Advanced)'
|
|
258
|
-
matterTypeLabel.style.display = showMatterType ? 'block' : 'none'
|
|
259
|
-
matterTypeLabel.style.marginBottom = '6px'
|
|
260
|
-
matterTypeLabel.style.fontWeight = '500'
|
|
261
|
-
matterTypeLabel.style.fontSize = '12px'
|
|
262
|
-
matterTypeLabel.style.color = '#6b7280'
|
|
263
|
-
matterTypeLabel.style.marginTop = '2px'
|
|
264
|
-
const matterTypes = [
|
|
265
|
-
{ value: '', label: 'Auto-detect (recommended)' },
|
|
266
|
-
{ value: 0, label: 'Roller Shade (0)' },
|
|
267
|
-
{ value: 1, label: 'Roman Shade (1)' },
|
|
268
|
-
{ value: 2, label: 'Balloon Shade (2)' },
|
|
269
|
-
{ value: 3, label: 'Woven Wood (3)' },
|
|
270
|
-
{ value: 4, label: 'Drapery (4)' },
|
|
271
|
-
{ value: 5, label: 'Awning (5)' },
|
|
272
|
-
{ value: 6, label: 'Shutter (6)' },
|
|
273
|
-
{ value: 7, label: 'Tilt Blind (7)' },
|
|
274
|
-
{ value: 8, label: 'Blind Tilt (8)' },
|
|
275
|
-
{ value: 9, label: 'Projector Screen (9)' },
|
|
276
|
-
{ value: 15, label: 'Other (15)' },
|
|
277
|
-
]
|
|
278
|
-
const matterTypeSelect = document.createElement('select')
|
|
279
|
-
matterTypeSelect.style.width = '100%'
|
|
280
|
-
matterTypeSelect.style.marginBottom = '12px'
|
|
281
|
-
matterTypeSelect.style.padding = '8px 10px'
|
|
282
|
-
matterTypeSelect.style.borderRadius = '6px'
|
|
283
|
-
matterTypeSelect.style.fontSize = '14px'
|
|
284
|
-
matterTypeSelect.style.boxSizing = 'border-box'
|
|
285
|
-
matterTypes.forEach((opt) => {
|
|
286
|
-
const option = document.createElement('option')
|
|
287
|
-
option.value = String(opt.value)
|
|
288
|
-
option.textContent = opt.label
|
|
289
|
-
if (device.matterType != null && String(opt.value) === String(device.matterType)) {
|
|
290
|
-
option.selected = true
|
|
291
|
-
}
|
|
292
|
-
matterTypeSelect.appendChild(option)
|
|
293
|
-
})
|
|
294
|
-
function updateMatterTypeVisibility() {
|
|
295
|
-
if (windowCoveringTypes.includes(typeSelect.value)) {
|
|
296
|
-
matterTypeLabel.style.display = 'block'
|
|
297
|
-
matterTypeSelect.style.display = 'block'
|
|
298
|
-
} else {
|
|
299
|
-
matterTypeLabel.style.display = 'none'
|
|
300
|
-
matterTypeSelect.style.display = 'none'
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
typeSelect.addEventListener('change', updateMatterTypeVisibility)
|
|
304
|
-
updateMatterTypeVisibility()
|
|
305
320
|
// Create modal dialog for editing
|
|
306
321
|
const div = document.createElement('div')
|
|
307
322
|
div.style.position = 'fixed'
|
|
@@ -402,6 +417,90 @@ export async function editDevice(device: any): Promise<void> {
|
|
|
402
417
|
typeSelect.appendChild(optgroup)
|
|
403
418
|
})
|
|
404
419
|
|
|
420
|
+
// --- Connection Preference ---
|
|
421
|
+
const connectionPrefLabel = document.createElement('label')
|
|
422
|
+
connectionPrefLabel.textContent = 'Connection Preference'
|
|
423
|
+
connectionPrefLabel.style.display = 'block'
|
|
424
|
+
connectionPrefLabel.style.marginBottom = '6px'
|
|
425
|
+
connectionPrefLabel.style.fontWeight = '500'
|
|
426
|
+
connectionPrefLabel.style.fontSize = '12px'
|
|
427
|
+
connectionPrefLabel.style.color = '#6b7280'
|
|
428
|
+
|
|
429
|
+
const connectionPrefSelect = document.createElement('select')
|
|
430
|
+
connectionPrefSelect.style.width = '100%'
|
|
431
|
+
connectionPrefSelect.style.marginBottom = '12px'
|
|
432
|
+
connectionPrefSelect.style.padding = '8px 10px'
|
|
433
|
+
connectionPrefSelect.style.borderRadius = '6px'
|
|
434
|
+
connectionPrefSelect.style.fontSize = '14px'
|
|
435
|
+
connectionPrefSelect.style.boxSizing = 'border-box'
|
|
436
|
+
;['auto', 'ble', 'openapi'].forEach((val) => {
|
|
437
|
+
const opt = document.createElement('option')
|
|
438
|
+
opt.value = val
|
|
439
|
+
opt.text = val.charAt(0).toUpperCase() + val.slice(1)
|
|
440
|
+
opt.selected = (device.connectionPreference || 'auto') === val
|
|
441
|
+
connectionPrefSelect.appendChild(opt)
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
// --- Room ---
|
|
445
|
+
const roomLabel = document.createElement('label')
|
|
446
|
+
roomLabel.textContent = 'Room'
|
|
447
|
+
roomLabel.style.display = 'block'
|
|
448
|
+
roomLabel.style.marginBottom = '6px'
|
|
449
|
+
roomLabel.style.fontWeight = '500'
|
|
450
|
+
roomLabel.style.fontSize = '12px'
|
|
451
|
+
roomLabel.style.color = '#6b7280'
|
|
452
|
+
|
|
453
|
+
const roomInput = document.createElement('input')
|
|
454
|
+
roomInput.type = 'text'
|
|
455
|
+
roomInput.value = device.room || ''
|
|
456
|
+
roomInput.placeholder = 'Optional room/location metadata'
|
|
457
|
+
roomInput.style.width = '100%'
|
|
458
|
+
roomInput.style.marginBottom = '12px'
|
|
459
|
+
roomInput.style.padding = '8px 10px'
|
|
460
|
+
roomInput.style.borderRadius = '6px'
|
|
461
|
+
roomInput.style.fontSize = '14px'
|
|
462
|
+
roomInput.style.boxSizing = 'border-box'
|
|
463
|
+
|
|
464
|
+
// --- Encryption Key ---
|
|
465
|
+
const encryptionKeyLabel = document.createElement('label')
|
|
466
|
+
encryptionKeyLabel.textContent = 'BLE Encryption Key (optional)'
|
|
467
|
+
encryptionKeyLabel.style.display = 'block'
|
|
468
|
+
encryptionKeyLabel.style.marginBottom = '6px'
|
|
469
|
+
encryptionKeyLabel.style.fontWeight = '500'
|
|
470
|
+
encryptionKeyLabel.style.fontSize = '12px'
|
|
471
|
+
encryptionKeyLabel.style.color = '#6b7280'
|
|
472
|
+
|
|
473
|
+
const encryptionKeyInput = document.createElement('input')
|
|
474
|
+
encryptionKeyInput.type = 'password'
|
|
475
|
+
encryptionKeyInput.value = device.encryptionKey || ''
|
|
476
|
+
encryptionKeyInput.placeholder = 'Paste device BLE encryption key'
|
|
477
|
+
encryptionKeyInput.style.width = '100%'
|
|
478
|
+
encryptionKeyInput.style.marginBottom = '12px'
|
|
479
|
+
encryptionKeyInput.style.padding = '8px 10px'
|
|
480
|
+
encryptionKeyInput.style.borderRadius = '6px'
|
|
481
|
+
encryptionKeyInput.style.fontSize = '14px'
|
|
482
|
+
encryptionKeyInput.style.boxSizing = 'border-box'
|
|
483
|
+
|
|
484
|
+
// --- Key ID ---
|
|
485
|
+
const keyIdLabel = document.createElement('label')
|
|
486
|
+
keyIdLabel.textContent = 'BLE Key ID (optional)'
|
|
487
|
+
keyIdLabel.style.display = 'block'
|
|
488
|
+
keyIdLabel.style.marginBottom = '6px'
|
|
489
|
+
keyIdLabel.style.fontWeight = '500'
|
|
490
|
+
keyIdLabel.style.fontSize = '12px'
|
|
491
|
+
keyIdLabel.style.color = '#6b7280'
|
|
492
|
+
|
|
493
|
+
const keyIdInput = document.createElement('input')
|
|
494
|
+
keyIdInput.type = 'text'
|
|
495
|
+
keyIdInput.value = device.keyId || ''
|
|
496
|
+
keyIdInput.placeholder = 'e.g. ff'
|
|
497
|
+
keyIdInput.style.width = '100%'
|
|
498
|
+
keyIdInput.style.marginBottom = '12px'
|
|
499
|
+
keyIdInput.style.padding = '8px 10px'
|
|
500
|
+
keyIdInput.style.borderRadius = '6px'
|
|
501
|
+
keyIdInput.style.fontSize = '14px'
|
|
502
|
+
keyIdInput.style.boxSizing = 'border-box'
|
|
503
|
+
|
|
405
504
|
const errorMessage = document.createElement('div')
|
|
406
505
|
errorMessage.style.color = 'var(--switchbot-red, #ef4444)'
|
|
407
506
|
errorMessage.style.marginBottom = '12px'
|
|
@@ -442,10 +541,32 @@ export async function editDevice(device: any): Promise<void> {
|
|
|
442
541
|
deviceId: device.id,
|
|
443
542
|
configDeviceName: nameInput.value || undefined,
|
|
444
543
|
configDeviceType: typeSelect.value,
|
|
445
|
-
|
|
544
|
+
connectionPreference: connectionPrefSelect.value,
|
|
545
|
+
room: roomInput.value || undefined,
|
|
546
|
+
encryptionKey: encryptionKeyInput.value || undefined,
|
|
547
|
+
keyId: keyIdInput.value || undefined,
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Only include defined properties in the options object
|
|
551
|
+
const options: any = {}
|
|
552
|
+
if (params.connectionPreference !== undefined) {
|
|
553
|
+
options.connectionPreference = params.connectionPreference
|
|
554
|
+
}
|
|
555
|
+
if (params.room !== undefined) {
|
|
556
|
+
options.room = params.room
|
|
557
|
+
}
|
|
558
|
+
if (params.encryptionKey !== undefined) {
|
|
559
|
+
options.encryptionKey = params.encryptionKey
|
|
560
|
+
}
|
|
561
|
+
if (params.keyId !== undefined) {
|
|
562
|
+
options.keyId = params.keyId
|
|
446
563
|
}
|
|
447
564
|
|
|
448
|
-
await updateDevice(
|
|
565
|
+
await updateDevice(
|
|
566
|
+
params.deviceId,
|
|
567
|
+
params.configDeviceName,
|
|
568
|
+
params.configDeviceType,
|
|
569
|
+
)
|
|
449
570
|
await syncParentPluginConfigFromDisk()
|
|
450
571
|
|
|
451
572
|
// Refresh device list
|
|
@@ -469,8 +590,14 @@ export async function editDevice(device: any): Promise<void> {
|
|
|
469
590
|
contentDiv.appendChild(apiTypeInput)
|
|
470
591
|
contentDiv.appendChild(typeLabel)
|
|
471
592
|
contentDiv.appendChild(typeSelect)
|
|
472
|
-
contentDiv.appendChild(
|
|
473
|
-
contentDiv.appendChild(
|
|
593
|
+
contentDiv.appendChild(connectionPrefLabel)
|
|
594
|
+
contentDiv.appendChild(connectionPrefSelect)
|
|
595
|
+
contentDiv.appendChild(roomLabel)
|
|
596
|
+
contentDiv.appendChild(roomInput)
|
|
597
|
+
contentDiv.appendChild(encryptionKeyLabel)
|
|
598
|
+
contentDiv.appendChild(encryptionKeyInput)
|
|
599
|
+
contentDiv.appendChild(keyIdLabel)
|
|
600
|
+
contentDiv.appendChild(keyIdInput)
|
|
474
601
|
contentDiv.appendChild(errorMessage)
|
|
475
602
|
contentDiv.appendChild(buttons)
|
|
476
603
|
|