@switchbot/homebridge-switchbot 5.0.0-beta.77 → 5.0.0-beta.79
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/dist/homebridge-ui/public/index.html +130 -1
- package/dist/homebridge-ui/server.d.ts.map +1 -1
- package/dist/homebridge-ui/server.js +102 -0
- package/dist/homebridge-ui/server.js.map +1 -1
- package/docs/variables/default.html +1 -1
- package/package.json +1 -1
- package/src/homebridge-ui/public/index.html +130 -1
- package/src/homebridge-ui/server.ts +119 -0
|
@@ -48,6 +48,17 @@
|
|
|
48
48
|
<div id="saveStatus"></div>
|
|
49
49
|
</div>
|
|
50
50
|
|
|
51
|
+
<div class="card">
|
|
52
|
+
<h2>Discover Devices</h2>
|
|
53
|
+
<p>Click "Discover" to find all devices available in your SwitchBot account and add them to your configuration.</p>
|
|
54
|
+
<button id="discoverBtn" onclick="discoverDevices()" style="margin-bottom: 16px">🔍 Discover Devices</button>
|
|
55
|
+
<div id="discoverStatus" style="margin-bottom: 16px"></div>
|
|
56
|
+
<div id="discoveredList" style="display: none">
|
|
57
|
+
<h3 style="margin-top: 0">Available Devices</h3>
|
|
58
|
+
<ul id="discoveredDevices" style="max-height: 300px; overflow-y: auto"></ul>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
51
62
|
<div class="card">
|
|
52
63
|
<h2>Configured Devices</h2>
|
|
53
64
|
<p>This page lists devices found in your Homebridge config for the SwitchBot platform. Use the copy button to insert device IDs into the plugin configuration. Connection preference (BLE/OpenAPI) is shown when available.</p>
|
|
@@ -144,7 +155,7 @@
|
|
|
144
155
|
async function fetchDevices() {
|
|
145
156
|
try {
|
|
146
157
|
const resp = await homebridge.request('/devices', {})
|
|
147
|
-
if (!resp ||
|
|
158
|
+
if (!resp || resp.success === false) throw new Error(resp?.data?.message || 'request failed')
|
|
148
159
|
return resp.data || []
|
|
149
160
|
} catch (e) {
|
|
150
161
|
console.error(e)
|
|
@@ -152,6 +163,124 @@
|
|
|
152
163
|
}
|
|
153
164
|
}
|
|
154
165
|
|
|
166
|
+
async function discoverDevices() {
|
|
167
|
+
const btn = document.getElementById('discoverBtn')
|
|
168
|
+
const status = document.getElementById('discoverStatus')
|
|
169
|
+
const list = document.getElementById('discoveredList')
|
|
170
|
+
const ul = document.getElementById('discoveredDevices')
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
btn.disabled = true
|
|
174
|
+
btn.textContent = '🔍 Discovering...'
|
|
175
|
+
status.textContent = 'Searching SwitchBot account...'
|
|
176
|
+
status.classList.remove('error')
|
|
177
|
+
|
|
178
|
+
const resp = await homebridge.request('/discover', {})
|
|
179
|
+
console.log('Discover response:', resp)
|
|
180
|
+
|
|
181
|
+
if (!resp || resp.success === false) {
|
|
182
|
+
throw new Error(resp?.data?.message || 'Discovery failed')
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const devices = resp.data || []
|
|
186
|
+
|
|
187
|
+
if (!devices.length) {
|
|
188
|
+
status.textContent = 'No devices found in your SwitchBot account'
|
|
189
|
+
list.style.display = 'none'
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
status.textContent = `Found ${devices.length} device(s)`
|
|
194
|
+
ul.innerHTML = ''
|
|
195
|
+
|
|
196
|
+
for (const d of devices) {
|
|
197
|
+
const li = document.createElement('li')
|
|
198
|
+
li.style.display = 'flex'
|
|
199
|
+
li.style.gap = '8px'
|
|
200
|
+
li.style.alignItems = 'center'
|
|
201
|
+
li.style.justifyContent = 'space-between'
|
|
202
|
+
li.style.padding = '8px'
|
|
203
|
+
li.style.background = '#333'
|
|
204
|
+
li.style.borderRadius = '4px'
|
|
205
|
+
li.style.marginBottom = '8px'
|
|
206
|
+
|
|
207
|
+
const info = document.createElement('div')
|
|
208
|
+
info.style.flex = '1'
|
|
209
|
+
const name = document.createElement('div')
|
|
210
|
+
name.style.fontWeight = '500'
|
|
211
|
+
name.textContent = d.name || d.id
|
|
212
|
+
const details = document.createElement('div')
|
|
213
|
+
details.style.fontSize = '12px'
|
|
214
|
+
details.style.opacity = '0.75'
|
|
215
|
+
details.textContent = `ID: ${d.id} | Type: ${d.type} | Model: ${d.model || 'N/A'}`
|
|
216
|
+
info.appendChild(name)
|
|
217
|
+
info.appendChild(details)
|
|
218
|
+
|
|
219
|
+
const addBtn = document.createElement('button')
|
|
220
|
+
addBtn.textContent = '+ Add'
|
|
221
|
+
addBtn.style.marginLeft = '8px'
|
|
222
|
+
addBtn.onclick = async () => {
|
|
223
|
+
await addDeviceToConfig(d)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
li.appendChild(info)
|
|
227
|
+
li.appendChild(addBtn)
|
|
228
|
+
ul.appendChild(li)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
list.style.display = 'block'
|
|
232
|
+
} catch (e) {
|
|
233
|
+
console.error('Discovery error:', e)
|
|
234
|
+
status.textContent = 'Error: ' + (e?.message || 'Discovery failed')
|
|
235
|
+
status.classList.add('error')
|
|
236
|
+
list.style.display = 'none'
|
|
237
|
+
} finally {
|
|
238
|
+
btn.disabled = false
|
|
239
|
+
btn.textContent = '🔍 Discover Devices'
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function addDeviceToConfig(device) {
|
|
244
|
+
try {
|
|
245
|
+
console.log('Adding device to config:', device)
|
|
246
|
+
|
|
247
|
+
const resp = await homebridge.request('/add-device', {
|
|
248
|
+
deviceId: device.id,
|
|
249
|
+
name: device.name,
|
|
250
|
+
type: device.type,
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
console.log('Add device response:', resp)
|
|
254
|
+
|
|
255
|
+
if (!resp || resp.success === false) {
|
|
256
|
+
throw new Error(resp?.data?.message || 'Failed to add device')
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Show success message
|
|
260
|
+
const message = resp.data?.message || `Device "${device.name}" added successfully!`
|
|
261
|
+
const status = document.getElementById('discoverStatus')
|
|
262
|
+
status.textContent = '✓ ' + message
|
|
263
|
+
status.classList.remove('error')
|
|
264
|
+
status.classList.add('success-msg')
|
|
265
|
+
|
|
266
|
+
// Refresh lists after 1 second
|
|
267
|
+
setTimeout(async () => {
|
|
268
|
+
await loadConfiguredDevices()
|
|
269
|
+
await discoverDevices()
|
|
270
|
+
}, 1000)
|
|
271
|
+
} catch (e) {
|
|
272
|
+
console.error('Add device error:', e)
|
|
273
|
+
const status = document.getElementById('discoverStatus')
|
|
274
|
+
status.textContent = '✗ Error: ' + (e?.message || 'Failed to add device')
|
|
275
|
+
status.classList.add('error')
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async function loadConfiguredDevices() {
|
|
280
|
+
const list = await fetchDevices()
|
|
281
|
+
render(list)
|
|
282
|
+
}
|
|
283
|
+
|
|
155
284
|
function render(list) {
|
|
156
285
|
const ul = document.getElementById('devices')
|
|
157
286
|
const status = document.getElementById('status')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/homebridge-ui/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAgB,MAAM,6BAA6B,CAAA;AAGpF,QAAA,MAAM,MAAM,0BAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/homebridge-ui/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAgB,MAAM,6BAA6B,CAAA;AAGpF,QAAA,MAAM,MAAM,0BAAiC,CAAA;AAoP7C,eAAe,MAAM,CAAA"}
|
|
@@ -65,6 +65,108 @@ server.onRequest('/devices', async () => {
|
|
|
65
65
|
throw new RequestError('Failed to read Homebridge config', e);
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
|
+
server.onRequest('/discover', async () => {
|
|
69
|
+
try {
|
|
70
|
+
const { platform } = await getSwitchBotPlatformConfig();
|
|
71
|
+
console.log('[SwitchBot UI] GET /discover - Platform config:', Object.keys(platform));
|
|
72
|
+
const token = platform.openApiToken || platform.token;
|
|
73
|
+
if (!token) {
|
|
74
|
+
console.error('[SwitchBot UI] No API token found in platform config');
|
|
75
|
+
throw new Error('OpenAPI token not configured. Please save your credentials first.');
|
|
76
|
+
}
|
|
77
|
+
console.log('[SwitchBot UI] GET /discover - Fetching devices from SwitchBot API');
|
|
78
|
+
const url = 'https://api.switch-bot.com/v1.0/devices';
|
|
79
|
+
const opts = {
|
|
80
|
+
headers: {
|
|
81
|
+
Authorization: token,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
console.log('[SwitchBot UI] GET /discover - Making request to', url);
|
|
85
|
+
const resp = await fetch(url, opts);
|
|
86
|
+
console.log('[SwitchBot UI] GET /discover - API response status:', resp.status);
|
|
87
|
+
if (!resp.ok) {
|
|
88
|
+
const errorText = await resp.text();
|
|
89
|
+
console.error('[SwitchBot UI] API error response:', errorText);
|
|
90
|
+
throw new Error(`SwitchBot API returned ${resp.status}: ${errorText}`);
|
|
91
|
+
}
|
|
92
|
+
const data = await resp.json();
|
|
93
|
+
console.log('[SwitchBot UI] GET /discover - Full API response:', JSON.stringify(data, null, 2));
|
|
94
|
+
// Handle different response formats
|
|
95
|
+
let devices = [];
|
|
96
|
+
if (Array.isArray(data)) {
|
|
97
|
+
devices = data;
|
|
98
|
+
}
|
|
99
|
+
else if (Array.isArray(data.body)) {
|
|
100
|
+
devices = data.body;
|
|
101
|
+
}
|
|
102
|
+
else if (Array.isArray(data.devices)) {
|
|
103
|
+
devices = data.devices;
|
|
104
|
+
}
|
|
105
|
+
else if (data.body && typeof data.body === 'object') {
|
|
106
|
+
// Sometimes the response has devices listed within body
|
|
107
|
+
const bodyKeys = Object.keys(data.body);
|
|
108
|
+
if (bodyKeys.includes('deviceList')) {
|
|
109
|
+
devices = Array.isArray(data.body.deviceList) ? data.body.deviceList : [];
|
|
110
|
+
}
|
|
111
|
+
else if (bodyKeys.includes('devices')) {
|
|
112
|
+
devices = Array.isArray(data.body.devices) ? data.body.devices : [];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (!Array.isArray(devices)) {
|
|
116
|
+
console.warn('[SwitchBot UI] Could not find devices array in API response. Response keys:', Object.keys(data), 'Body keys:', data.body ? Object.keys(data.body) : 'N/A');
|
|
117
|
+
devices = [];
|
|
118
|
+
}
|
|
119
|
+
const discovered = devices.map((d) => ({
|
|
120
|
+
id: d.deviceId || d.id,
|
|
121
|
+
name: d.deviceName || d.name,
|
|
122
|
+
type: d.deviceType || d.type || 'unknown',
|
|
123
|
+
model: d.deviceModel || d.model,
|
|
124
|
+
enabled: d.enableCloudService !== false,
|
|
125
|
+
}));
|
|
126
|
+
console.log('[SwitchBot UI] GET /discover - Found', discovered.length, 'devices from API');
|
|
127
|
+
return { success: true, data: discovered };
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
console.error('[SwitchBot UI] Error in /discover:', e instanceof Error ? e.message : String(e));
|
|
131
|
+
throw new RequestError(`Failed to discover devices: ${e instanceof Error ? e.message : String(e)}`, e);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
server.onRequest('/add-device', async (body) => {
|
|
135
|
+
try {
|
|
136
|
+
const { deviceId, name, type } = body;
|
|
137
|
+
if (!deviceId) {
|
|
138
|
+
throw new Error('Device ID is required');
|
|
139
|
+
}
|
|
140
|
+
const { config, platform, cfgPath } = await getSwitchBotPlatformConfig();
|
|
141
|
+
console.log('[SwitchBot UI] POST /add-device - Adding device:', deviceId);
|
|
142
|
+
// Initialize devices array if needed
|
|
143
|
+
if (!Array.isArray(platform.devices)) {
|
|
144
|
+
platform.devices = [];
|
|
145
|
+
}
|
|
146
|
+
// Check if already exists
|
|
147
|
+
const exists = platform.devices.some((d) => (d.deviceId ?? d.id) === deviceId);
|
|
148
|
+
if (exists) {
|
|
149
|
+
return { success: false, data: { message: 'Device already in config' } };
|
|
150
|
+
}
|
|
151
|
+
// Add device
|
|
152
|
+
platform.devices.push({
|
|
153
|
+
deviceId,
|
|
154
|
+
configDeviceName: name,
|
|
155
|
+
configDeviceType: type,
|
|
156
|
+
});
|
|
157
|
+
// Save config
|
|
158
|
+
await fs.writeFile(cfgPath, JSON.stringify(config, null, 2), 'utf8');
|
|
159
|
+
console.log('[SwitchBot UI] Device added successfully:', deviceId);
|
|
160
|
+
return {
|
|
161
|
+
success: true,
|
|
162
|
+
data: { message: `Device "${name}" added successfully` },
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
console.error('[SwitchBot UI] Error in /add-device:', e);
|
|
167
|
+
throw new RequestError('Failed to add device', e);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
68
170
|
server.onRequest('/credentials', async (body) => {
|
|
69
171
|
try {
|
|
70
172
|
// Handle both GET and POST requests
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/homebridge-ui/server.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/homebridge-ui/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>default | @switchbot/homebridge-switchbot</title><meta name="description" content="Documentation for @switchbot/homebridge-switchbot"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@switchbot/homebridge-switchbot</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">default</a></li></ul><h1>Variable default</h1></div><div class="tsd-signature"><span class="tsd-kind-variable">default</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span> <span class="tsd-signature-symbol">=></span> <span class="tsd-signature-type">void</span></div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter-signature"><ul class="tsd-signatures"><li class="tsd-signature" id="__type"><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">void</span></li><li class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">api</span>: <span class="tsd-signature-type">API</span></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4></li></ul></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/
|
|
1
|
+
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>default | @switchbot/homebridge-switchbot</title><meta name="description" content="Documentation for @switchbot/homebridge-switchbot"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@switchbot/homebridge-switchbot</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">default</a></li></ul><h1>Variable default</h1></div><div class="tsd-signature"><span class="tsd-kind-variable">default</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span> <span class="tsd-signature-symbol">=></span> <span class="tsd-signature-type">void</span></div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter-signature"><ul class="tsd-signatures"><li class="tsd-signature" id="__type"><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">void</span></li><li class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">api</span>: <span class="tsd-signature-type">API</span></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4></li></ul></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/42cb2bab88e1db495b6b92e75a31f7cf34eb8670/src/index.ts#L12">index.ts:12</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">@switchbot/homebridge-switchbot</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer></footer><div class="overlay"></div></body></html>
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@switchbot/homebridge-switchbot",
|
|
3
3
|
"displayName": "SwitchBot",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "5.0.0-beta.
|
|
5
|
+
"version": "5.0.0-beta.79",
|
|
6
6
|
"description": "The SwitchBot plugin allows you to access your SwitchBot device(s) from HomeKit.",
|
|
7
7
|
"author": "SwitchBot <support@wondertechlabs.com> (https://github.com/SwitchBot)",
|
|
8
8
|
"contributors": [
|
|
@@ -48,6 +48,17 @@
|
|
|
48
48
|
<div id="saveStatus"></div>
|
|
49
49
|
</div>
|
|
50
50
|
|
|
51
|
+
<div class="card">
|
|
52
|
+
<h2>Discover Devices</h2>
|
|
53
|
+
<p>Click "Discover" to find all devices available in your SwitchBot account and add them to your configuration.</p>
|
|
54
|
+
<button id="discoverBtn" onclick="discoverDevices()" style="margin-bottom: 16px">🔍 Discover Devices</button>
|
|
55
|
+
<div id="discoverStatus" style="margin-bottom: 16px"></div>
|
|
56
|
+
<div id="discoveredList" style="display: none">
|
|
57
|
+
<h3 style="margin-top: 0">Available Devices</h3>
|
|
58
|
+
<ul id="discoveredDevices" style="max-height: 300px; overflow-y: auto"></ul>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
51
62
|
<div class="card">
|
|
52
63
|
<h2>Configured Devices</h2>
|
|
53
64
|
<p>This page lists devices found in your Homebridge config for the SwitchBot platform. Use the copy button to insert device IDs into the plugin configuration. Connection preference (BLE/OpenAPI) is shown when available.</p>
|
|
@@ -144,7 +155,7 @@
|
|
|
144
155
|
async function fetchDevices() {
|
|
145
156
|
try {
|
|
146
157
|
const resp = await homebridge.request('/devices', {})
|
|
147
|
-
if (!resp ||
|
|
158
|
+
if (!resp || resp.success === false) throw new Error(resp?.data?.message || 'request failed')
|
|
148
159
|
return resp.data || []
|
|
149
160
|
} catch (e) {
|
|
150
161
|
console.error(e)
|
|
@@ -152,6 +163,124 @@
|
|
|
152
163
|
}
|
|
153
164
|
}
|
|
154
165
|
|
|
166
|
+
async function discoverDevices() {
|
|
167
|
+
const btn = document.getElementById('discoverBtn')
|
|
168
|
+
const status = document.getElementById('discoverStatus')
|
|
169
|
+
const list = document.getElementById('discoveredList')
|
|
170
|
+
const ul = document.getElementById('discoveredDevices')
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
btn.disabled = true
|
|
174
|
+
btn.textContent = '🔍 Discovering...'
|
|
175
|
+
status.textContent = 'Searching SwitchBot account...'
|
|
176
|
+
status.classList.remove('error')
|
|
177
|
+
|
|
178
|
+
const resp = await homebridge.request('/discover', {})
|
|
179
|
+
console.log('Discover response:', resp)
|
|
180
|
+
|
|
181
|
+
if (!resp || resp.success === false) {
|
|
182
|
+
throw new Error(resp?.data?.message || 'Discovery failed')
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const devices = resp.data || []
|
|
186
|
+
|
|
187
|
+
if (!devices.length) {
|
|
188
|
+
status.textContent = 'No devices found in your SwitchBot account'
|
|
189
|
+
list.style.display = 'none'
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
status.textContent = `Found ${devices.length} device(s)`
|
|
194
|
+
ul.innerHTML = ''
|
|
195
|
+
|
|
196
|
+
for (const d of devices) {
|
|
197
|
+
const li = document.createElement('li')
|
|
198
|
+
li.style.display = 'flex'
|
|
199
|
+
li.style.gap = '8px'
|
|
200
|
+
li.style.alignItems = 'center'
|
|
201
|
+
li.style.justifyContent = 'space-between'
|
|
202
|
+
li.style.padding = '8px'
|
|
203
|
+
li.style.background = '#333'
|
|
204
|
+
li.style.borderRadius = '4px'
|
|
205
|
+
li.style.marginBottom = '8px'
|
|
206
|
+
|
|
207
|
+
const info = document.createElement('div')
|
|
208
|
+
info.style.flex = '1'
|
|
209
|
+
const name = document.createElement('div')
|
|
210
|
+
name.style.fontWeight = '500'
|
|
211
|
+
name.textContent = d.name || d.id
|
|
212
|
+
const details = document.createElement('div')
|
|
213
|
+
details.style.fontSize = '12px'
|
|
214
|
+
details.style.opacity = '0.75'
|
|
215
|
+
details.textContent = `ID: ${d.id} | Type: ${d.type} | Model: ${d.model || 'N/A'}`
|
|
216
|
+
info.appendChild(name)
|
|
217
|
+
info.appendChild(details)
|
|
218
|
+
|
|
219
|
+
const addBtn = document.createElement('button')
|
|
220
|
+
addBtn.textContent = '+ Add'
|
|
221
|
+
addBtn.style.marginLeft = '8px'
|
|
222
|
+
addBtn.onclick = async () => {
|
|
223
|
+
await addDeviceToConfig(d)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
li.appendChild(info)
|
|
227
|
+
li.appendChild(addBtn)
|
|
228
|
+
ul.appendChild(li)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
list.style.display = 'block'
|
|
232
|
+
} catch (e) {
|
|
233
|
+
console.error('Discovery error:', e)
|
|
234
|
+
status.textContent = 'Error: ' + (e?.message || 'Discovery failed')
|
|
235
|
+
status.classList.add('error')
|
|
236
|
+
list.style.display = 'none'
|
|
237
|
+
} finally {
|
|
238
|
+
btn.disabled = false
|
|
239
|
+
btn.textContent = '🔍 Discover Devices'
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function addDeviceToConfig(device) {
|
|
244
|
+
try {
|
|
245
|
+
console.log('Adding device to config:', device)
|
|
246
|
+
|
|
247
|
+
const resp = await homebridge.request('/add-device', {
|
|
248
|
+
deviceId: device.id,
|
|
249
|
+
name: device.name,
|
|
250
|
+
type: device.type,
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
console.log('Add device response:', resp)
|
|
254
|
+
|
|
255
|
+
if (!resp || resp.success === false) {
|
|
256
|
+
throw new Error(resp?.data?.message || 'Failed to add device')
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Show success message
|
|
260
|
+
const message = resp.data?.message || `Device "${device.name}" added successfully!`
|
|
261
|
+
const status = document.getElementById('discoverStatus')
|
|
262
|
+
status.textContent = '✓ ' + message
|
|
263
|
+
status.classList.remove('error')
|
|
264
|
+
status.classList.add('success-msg')
|
|
265
|
+
|
|
266
|
+
// Refresh lists after 1 second
|
|
267
|
+
setTimeout(async () => {
|
|
268
|
+
await loadConfiguredDevices()
|
|
269
|
+
await discoverDevices()
|
|
270
|
+
}, 1000)
|
|
271
|
+
} catch (e) {
|
|
272
|
+
console.error('Add device error:', e)
|
|
273
|
+
const status = document.getElementById('discoverStatus')
|
|
274
|
+
status.textContent = '✗ Error: ' + (e?.message || 'Failed to add device')
|
|
275
|
+
status.classList.add('error')
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async function loadConfiguredDevices() {
|
|
280
|
+
const list = await fetchDevices()
|
|
281
|
+
render(list)
|
|
282
|
+
}
|
|
283
|
+
|
|
155
284
|
function render(list) {
|
|
156
285
|
const ul = document.getElementById('devices')
|
|
157
286
|
const status = document.getElementById('status')
|
|
@@ -75,6 +75,125 @@ server.onRequest('/devices', async () => {
|
|
|
75
75
|
}
|
|
76
76
|
})
|
|
77
77
|
|
|
78
|
+
server.onRequest('/discover', async () => {
|
|
79
|
+
try {
|
|
80
|
+
const { platform } = await getSwitchBotPlatformConfig()
|
|
81
|
+
|
|
82
|
+
console.log('[SwitchBot UI] GET /discover - Platform config:', Object.keys(platform))
|
|
83
|
+
|
|
84
|
+
const token = platform.openApiToken || platform.token
|
|
85
|
+
if (!token) {
|
|
86
|
+
console.error('[SwitchBot UI] No API token found in platform config')
|
|
87
|
+
throw new Error('OpenAPI token not configured. Please save your credentials first.')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log('[SwitchBot UI] GET /discover - Fetching devices from SwitchBot API')
|
|
91
|
+
|
|
92
|
+
const url = 'https://api.switch-bot.com/v1.0/devices'
|
|
93
|
+
const opts = {
|
|
94
|
+
headers: {
|
|
95
|
+
Authorization: token,
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log('[SwitchBot UI] GET /discover - Making request to', url)
|
|
100
|
+
const resp = await fetch(url, opts)
|
|
101
|
+
|
|
102
|
+
console.log('[SwitchBot UI] GET /discover - API response status:', resp.status)
|
|
103
|
+
|
|
104
|
+
if (!resp.ok) {
|
|
105
|
+
const errorText = await resp.text()
|
|
106
|
+
console.error('[SwitchBot UI] API error response:', errorText)
|
|
107
|
+
throw new Error(`SwitchBot API returned ${resp.status}: ${errorText}`)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const data = await resp.json()
|
|
111
|
+
console.log('[SwitchBot UI] GET /discover - Full API response:', JSON.stringify(data, null, 2))
|
|
112
|
+
|
|
113
|
+
// Handle different response formats
|
|
114
|
+
let devices: any[] = []
|
|
115
|
+
if (Array.isArray(data)) {
|
|
116
|
+
devices = data
|
|
117
|
+
} else if (Array.isArray(data.body)) {
|
|
118
|
+
devices = data.body
|
|
119
|
+
} else if (Array.isArray(data.devices)) {
|
|
120
|
+
devices = data.devices
|
|
121
|
+
} else if (data.body && typeof data.body === 'object') {
|
|
122
|
+
// Sometimes the response has devices listed within body
|
|
123
|
+
const bodyKeys = Object.keys(data.body)
|
|
124
|
+
if (bodyKeys.includes('deviceList')) {
|
|
125
|
+
devices = Array.isArray(data.body.deviceList) ? data.body.deviceList : []
|
|
126
|
+
} else if (bodyKeys.includes('devices')) {
|
|
127
|
+
devices = Array.isArray(data.body.devices) ? data.body.devices : []
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!Array.isArray(devices)) {
|
|
132
|
+
console.warn('[SwitchBot UI] Could not find devices array in API response. Response keys:', Object.keys(data), 'Body keys:', data.body ? Object.keys(data.body) : 'N/A')
|
|
133
|
+
devices = []
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const discovered = devices.map((d: any) => ({
|
|
137
|
+
id: d.deviceId || d.id,
|
|
138
|
+
name: d.deviceName || d.name,
|
|
139
|
+
type: d.deviceType || d.type || 'unknown',
|
|
140
|
+
model: d.deviceModel || d.model,
|
|
141
|
+
enabled: d.enableCloudService !== false,
|
|
142
|
+
}))
|
|
143
|
+
|
|
144
|
+
console.log('[SwitchBot UI] GET /discover - Found', discovered.length, 'devices from API')
|
|
145
|
+
return { success: true, data: discovered }
|
|
146
|
+
} catch (e) {
|
|
147
|
+
console.error('[SwitchBot UI] Error in /discover:', e instanceof Error ? e.message : String(e))
|
|
148
|
+
throw new RequestError(`Failed to discover devices: ${e instanceof Error ? e.message : String(e)}`, e)
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
server.onRequest('/add-device', async (body: any) => {
|
|
153
|
+
try {
|
|
154
|
+
const { deviceId, name, type } = body
|
|
155
|
+
|
|
156
|
+
if (!deviceId) {
|
|
157
|
+
throw new Error('Device ID is required')
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const { config, platform, cfgPath } = await getSwitchBotPlatformConfig()
|
|
161
|
+
|
|
162
|
+
console.log('[SwitchBot UI] POST /add-device - Adding device:', deviceId)
|
|
163
|
+
|
|
164
|
+
// Initialize devices array if needed
|
|
165
|
+
if (!Array.isArray(platform.devices)) {
|
|
166
|
+
platform.devices = []
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Check if already exists
|
|
170
|
+
const exists = platform.devices.some((d: any) => (d.deviceId ?? d.id) === deviceId)
|
|
171
|
+
if (exists) {
|
|
172
|
+
return { success: false, data: { message: 'Device already in config' } }
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Add device
|
|
176
|
+
platform.devices.push({
|
|
177
|
+
deviceId,
|
|
178
|
+
configDeviceName: name,
|
|
179
|
+
configDeviceType: type,
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
// Save config
|
|
183
|
+
await fs.writeFile(cfgPath, JSON.stringify(config, null, 2), 'utf8')
|
|
184
|
+
|
|
185
|
+
console.log('[SwitchBot UI] Device added successfully:', deviceId)
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
success: true,
|
|
189
|
+
data: { message: `Device "${name}" added successfully` },
|
|
190
|
+
}
|
|
191
|
+
} catch (e) {
|
|
192
|
+
console.error('[SwitchBot UI] Error in /add-device:', e)
|
|
193
|
+
throw new RequestError('Failed to add device', e)
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
|
|
78
197
|
server.onRequest('/credentials', async (body: any) => {
|
|
79
198
|
try {
|
|
80
199
|
// Handle both GET and POST requests
|